bb4088dc7a05a69cef03ad5e9cc95c58ffeed053
[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 "al_debug.h"\r
44 #include "bus_port_mgr.h"\r
45 #include "bus_iou_mgr.h"\r
46 #include "complib/cl_memory.h"\r
47 #include <initguid.h>\r
48 #include "iba/ib_ci_ifc.h"\r
49 #include "iba/ib_cm_ifc.h"\r
50 #include "al_cm_cep.h"\r
51 #include "al_mgr.h"\r
52 #include "bus_ev_log.h"\r
53 \r
54 \r
55 /* Interface names are generated by IoRegisterDeviceInterface. */\r
56 static UNICODE_STRING   al_ifc_name;\r
57 static UNICODE_STRING   ci_ifc_name;\r
58 static UNICODE_STRING   cm_ifc_name;\r
59 \r
60 KEVENT                                  g_ControlEvent;\r
61 ULONG                                   g_bfi_InstanceCount;\r
62 bus_filter_t                    g_bus_filters[MAX_BUS_FILTERS];\r
63 \r
64 extern PDEVICE_OBJECT   g_ControlDeviceObject;\r
65 extern UNICODE_STRING   g_CDO_dev_name, g_CDO_dos_name;\r
66 \r
67 \r
68 static NTSTATUS\r
69 fdo_start(\r
70         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
71         IN                                      IRP* const                              p_irp, \r
72                 OUT                             cl_irp_action_t* const  p_action );\r
73 \r
74 static void\r
75 fdo_release_resources(\r
76         IN                                      DEVICE_OBJECT* const    p_dev_obj );\r
77 \r
78 static NTSTATUS\r
79 fdo_query_remove(\r
80         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
81         IN                                      IRP* const                              p_irp, \r
82                 OUT                             cl_irp_action_t* const  p_action );\r
83 \r
84 static NTSTATUS\r
85 fdo_query_capabilities(\r
86         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
87         IN                                      IRP* const                              p_irp, \r
88                 OUT                             cl_irp_action_t* const  p_action );\r
89 \r
90 static NTSTATUS\r
91 fdo_query_bus_relations(\r
92         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
93         IN                                      IRP* const                              p_irp, \r
94                 OUT                             cl_irp_action_t* const  p_action );\r
95 \r
96 static NTSTATUS\r
97 __query_al_ifc(\r
98         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
99         IN                              IO_STACK_LOCATION* const        p_io_stack );\r
100 \r
101 static NTSTATUS\r
102 __get_relations(\r
103         IN              const   net64_t                                         ca_guid,\r
104         IN                              IRP* const                                      p_irp );\r
105 \r
106 static NTSTATUS\r
107 __query_ci_ifc(\r
108         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
109         IN                              IO_STACK_LOCATION* const        p_io_stack );\r
110 \r
111 static NTSTATUS\r
112 __query_cm_ifc(\r
113         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
114         IN                              IO_STACK_LOCATION* const        p_io_stack );\r
115 \r
116 static NTSTATUS\r
117 fdo_query_pnp_state(\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 static NTSTATUS\r
124 fdo_query_interface(\r
125         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
126         IN                              IRP* const                                      p_irp, \r
127                 OUT                     cl_irp_action_t* const          p_action );\r
128 \r
129 static NTSTATUS\r
130 __fdo_query_power(\r
131         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
132         IN                              IRP* const                                      p_irp,\r
133                 OUT                     cl_irp_action_t* const          p_action );\r
134 \r
135 static NTSTATUS\r
136 __fdo_set_power(\r
137         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
138         IN                              IRP* const                                      p_irp,\r
139                 OUT                     cl_irp_action_t* const          p_action );\r
140 \r
141 static void\r
142 __set_ifc(\r
143                 OUT                     ib_al_ifc_t* const                      p_ifc );\r
144 \r
145 \r
146 \r
147 \r
148 /* Global virtual function pointer tables shared between all instances of FDO. */\r
149 static const cl_vfptr_pnp_po_t          vfptr_fdo_pnp = {\r
150         "IB Bus",\r
151         fdo_start,\r
152         cl_irp_skip,\r
153         cl_irp_skip,\r
154         cl_do_sync_pnp,\r
155         fdo_query_remove,\r
156         fdo_release_resources,\r
157         cl_do_remove,\r
158         cl_do_sync_pnp,\r
159         cl_irp_skip,\r
160         fdo_query_capabilities,\r
161         fdo_query_pnp_state,\r
162         cl_irp_skip,\r
163         cl_do_sync_pnp,\r
164         fdo_query_bus_relations,\r
165         cl_irp_ignore,\r
166         cl_irp_skip,\r
167         cl_irp_ignore,\r
168         cl_irp_ignore,\r
169         cl_irp_ignore,\r
170         cl_irp_ignore,\r
171         cl_irp_ignore,\r
172         fdo_query_interface,    /* QueryInterface */\r
173         cl_irp_ignore,\r
174         cl_irp_ignore,\r
175         cl_irp_ignore,\r
176         cl_irp_ignore,\r
177         __fdo_query_power,              /* QueryPower */\r
178         __fdo_set_power,                /* SetPower */\r
179         cl_irp_ignore,                  /* PowerSequence */\r
180         cl_irp_ignore                   /* WaitWake */\r
181 };\r
182 \r
183 \r
184 NTSTATUS\r
185 bus_add_device(\r
186         IN                              DRIVER_OBJECT                           *p_driver_obj,\r
187         IN                              DEVICE_OBJECT                           *p_pdo )\r
188 {\r
189         NTSTATUS                status;\r
190         DEVICE_OBJECT   *p_dev_obj, *p_next_do;\r
191         bus_fdo_ext_t   *p_ext=NULL;\r
192         bus_filter_t    *p_bfi;\r
193         int                             ic;\r
194 \r
195         BUS_ENTER( BUS_DBG_PNP );\r
196 \r
197         /* allocate a Bus Filter Instance */\r
198         p_bfi = alloc_bfi( p_driver_obj, &ic );\r
199         if ( !p_bfi )\r
200         {\r
201                 BUS_TRACE_EXIT( BUS_DBG_PNP,\r
202                         ("%s() Err - Exceeded MAX_BUS_FILTERS(%d)\n",MAX_BUS_FILTERS));\r
203                 return STATUS_UNSUCCESSFUL;\r
204         }\r
205 \r
206         /* if 1st Bus Filter Instance, then create device names for user ioctl */\r
207         if ( ic == 1  && !g_ControlDeviceObject)\r
208         {\r
209                 RtlInitUnicodeString( &g_CDO_dev_name, AL_DEVICE_NAME );\r
210                 RtlInitUnicodeString( &g_CDO_dos_name, L"\\DosDevices\\Global\\ibal" );\r
211         \r
212                 status = IoCreateDevice( p_driver_obj, sizeof(bus_fdo_ext_t),\r
213                         &g_CDO_dev_name, FILE_DEVICE_BUS_EXTENDER,\r
214                         FILE_DEVICE_SECURE_OPEN, FALSE, &g_ControlDeviceObject );\r
215                 if( !NT_SUCCESS(status) )\r
216                 {\r
217                         g_ControlDeviceObject = NULL;\r
218                         BUS_PRINT( BUS_DBG_ERROR, \r
219                                 ("Failed to create ControlDeviceObject, status %x.\n",status) );\r
220                         goto err1;\r
221                 }\r
222                 else {\r
223                         p_ext = g_ControlDeviceObject->DeviceExtension;\r
224                         RtlZeroMemory(p_ext, sizeof *p_ext);\r
225                         cl_init_pnp_po_ext( g_ControlDeviceObject, NULL, \r
226                                                                 NULL, bus_globals.dbg_lvl, NULL, NULL );\r
227 \r
228                         /* enable user-mode access to IB stack */\r
229                         BUS_PRINT( BUS_DBG_PNP, ("Remove-n-reCreate dos_name symlink\n") );\r
230                         IoDeleteSymbolicLink( &g_CDO_dos_name );\r
231                         status = IoCreateSymbolicLink( &g_CDO_dos_name, &g_CDO_dev_name );\r
232                         if( !NT_SUCCESS(status) )\r
233                         {\r
234                                 BUS_PRINT( BUS_DBG_ERROR,\r
235                                         ("Failed to create symlink for dos name.\n") );\r
236                                 IoDeleteDevice( g_ControlDeviceObject );\r
237                                 g_ControlDeviceObject = NULL;\r
238                                 goto err1;\r
239                         }\r
240                         BUS_TRACE( BUS_DBG_PNP, ("Created dos_name symlink\n") );\r
241                 }\r
242         }\r
243 \r
244         /* Create the FDO device object to attach to the stack. */\r
245         status = IoCreateDevice( p_driver_obj, sizeof(bus_fdo_ext_t),\r
246                                                          NULL, FILE_DEVICE_BUS_EXTENDER,\r
247                                                          FILE_DEVICE_SECURE_OPEN, FALSE, &p_dev_obj );\r
248         if( !NT_SUCCESS(status) )\r
249         {\r
250                 BUS_PRINT( BUS_DBG_ERROR, \r
251                         ("Failed to create bus root FDO device.\n") );\r
252                 goto err1;\r
253         }\r
254 \r
255         p_ext = p_dev_obj->DeviceExtension;\r
256         cl_memclr( p_ext, sizeof(bus_fdo_ext_t) );\r
257 \r
258         p_next_do = IoAttachDeviceToDeviceStack( p_dev_obj, p_pdo );\r
259         if( !p_next_do )\r
260         {\r
261                 BUS_PRINT( BUS_DBG_ERROR, ("IoAttachToDeviceStack failed.\n") );\r
262                 status = STATUS_NO_SUCH_DEVICE;\r
263                 goto err2;\r
264         }\r
265 \r
266         cl_init_pnp_po_ext( p_dev_obj, p_next_do, p_pdo, bus_globals.dbg_lvl,\r
267                                                 &vfptr_fdo_pnp, NULL );\r
268 \r
269         p_bfi->p_bus_ext = p_ext;\r
270         p_ext->bus_filter = p_bfi;\r
271 \r
272         /*\r
273          * if not 1st Bus Filter Instance, then finished...\r
274          */\r
275         if ( ic > 1 )\r
276                 goto adxit;\r
277 \r
278         /* Register the upper interface (the one used by clients). */\r
279         status = IoRegisterDeviceInterface( p_pdo, &GUID_IB_AL_INTERFACE, NULL,\r
280                                                                                 &al_ifc_name );\r
281         if( !NT_SUCCESS( status ) )\r
282         {\r
283                 BUS_PRINT( BUS_DBG_ERROR, \r
284                         ("IoRegisterDeviceInterface for upper interface returned %08x\n",\r
285                         status) );\r
286                 status = STATUS_NO_SUCH_DEVICE;\r
287                 goto err3;\r
288         }\r
289 \r
290         /* Register the lower (CI) interface (the one used by HCA VPDs). */\r
291         status = IoRegisterDeviceInterface( p_pdo, &GUID_IB_CI_INTERFACE, NULL,\r
292                                                                                 &ci_ifc_name );\r
293         if( !NT_SUCCESS( status ) )\r
294         {\r
295                 BUS_PRINT( BUS_DBG_ERROR, \r
296                         ("IoRegisterDeviceInterface for lower interface returned %08x\n",\r
297                         status) );\r
298                 status = STATUS_NO_SUCH_DEVICE;\r
299                 goto err3;\r
300         }\r
301 \r
302         status = IoRegisterDeviceInterface( p_pdo, &GUID_INFINIBAND_INTERFACE_CM, NULL,\r
303                                                                                 &cm_ifc_name );\r
304         if( !NT_SUCCESS( status ) )\r
305         {\r
306                 BUS_PRINT( BUS_DBG_ERROR, \r
307                         ("IoRegisterDeviceInterface for cm interface returned %08x\n",\r
308                         status) );\r
309                 status = STATUS_NO_SUCH_DEVICE;\r
310                 goto err3;\r
311         }\r
312 \r
313 adxit:\r
314         BUS_PRINT( BUS_DBG_PNP, ("%s exit status 0\n", p_bfi->whoami) );\r
315 \r
316         BUS_EXIT( BUS_DBG_PNP );\r
317         return STATUS_SUCCESS;\r
318 \r
319 err3:\r
320         IoDetachDevice( p_ext->cl_ext.p_next_do );\r
321 err2:\r
322         IoDeleteDevice( p_dev_obj );\r
323 err1:\r
324         BUS_PRINT( BUS_DBG_PNP, ("%s exit status 0x%x\n", p_bfi->whoami,status) );\r
325         ic = free_bfi(p_bfi);\r
326         BUS_EXIT( BUS_DBG_PNP );\r
327         return status;\r
328 }\r
329 \r
330 \r
331 /* Forwards the request to the HCA's FDO. */\r
332 static NTSTATUS\r
333 __get_ifc(\r
334         IN                              DEVICE_OBJECT* const            pDevObj,\r
335         IN              const   GUID* const                                     pGuid,\r
336         IN                              USHORT                                          size,\r
337         IN                              USHORT                                          Version,\r
338         IN OUT                  PVOID                                           InterfaceSpecificData,\r
339                 OUT                     PINTERFACE                                      pHcaIfc )\r
340 {\r
341         NTSTATUS                        status;\r
342         IRP                                     *pIrp;\r
343         IO_STATUS_BLOCK         ioStatus;\r
344         IO_STACK_LOCATION       *pIoStack;\r
345         DEVICE_OBJECT           *pDev;\r
346         KEVENT                          event;\r
347 \r
348         BUS_ENTER( BUS_DBG_PNP );\r
349 \r
350         CL_ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );\r
351 \r
352         pDev = IoGetAttachedDeviceReference( pDevObj );\r
353 \r
354         KeInitializeEvent( &event, NotificationEvent, FALSE );\r
355 \r
356         /* Build the IRP for the HCA. */\r
357         pIrp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP, pDev,\r
358                 NULL, 0, NULL, &event, &ioStatus );\r
359         if( !pIrp )\r
360         {\r
361                 ObDereferenceObject( pDev );\r
362                 BUS_PRINT( BUS_DBG_PNP, \r
363                         ("IoBuildSynchronousFsdRequest failed.\n"));\r
364                 return STATUS_INSUFFICIENT_RESOURCES;\r
365         }\r
366 \r
367         /* Copy the request query parameters. */\r
368         pIoStack = IoGetNextIrpStackLocation( pIrp );\r
369         pIoStack->MinorFunction = IRP_MN_QUERY_INTERFACE;\r
370         pIoStack->Parameters.QueryInterface.Size = size;\r
371         pIoStack->Parameters.QueryInterface.Version = Version;\r
372         pIoStack->Parameters.QueryInterface.InterfaceType = pGuid;\r
373         pIoStack->Parameters.QueryInterface.Interface = (INTERFACE*)pHcaIfc;\r
374         pIoStack->Parameters.QueryInterface.InterfaceSpecificData = InterfaceSpecificData;\r
375 \r
376         pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;\r
377 \r
378         /* Send the IRP. */\r
379         status = IoCallDriver( pDev, pIrp );\r
380         if( status == STATUS_PENDING )\r
381         {\r
382                 KeWaitForSingleObject( &event, Executive, KernelMode,\r
383                         FALSE, NULL );\r
384 \r
385                 status = ioStatus.Status;\r
386         }\r
387         ObDereferenceObject( pDev );\r
388 \r
389         BUS_EXIT( BUS_DBG_PNP );\r
390         return status;\r
391 }\r
392 \r
393 \r
394 static NTSTATUS\r
395 __register_ca(\r
396         IN                                      DEVICE_OBJECT* const    p_dev_obj\r
397         )\r
398 {\r
399         NTSTATUS                status;\r
400         bus_fdo_ext_t   *p_ext;\r
401         ib_api_status_t ib_status;\r
402         bus_filter_t    *p_bfi;\r
403 \r
404         BUS_ENTER( BUS_DBG_PNP );\r
405 \r
406         p_ext = p_dev_obj->DeviceExtension;\r
407         p_bfi = p_ext->bus_filter;\r
408 \r
409         /* get HCA verbs interface */\r
410         status = __get_ifc( p_dev_obj, &GUID_RDMA_INTERFACE_VERBS,\r
411                                                 sizeof(RDMA_INTERFACE_VERBS), \r
412                                                 VerbsVersion(VERBS_MAJOR_VER, VERBS_MINOR_VER), \r
413                                                 p_ext, (PINTERFACE)&p_ext->hca_ifc );\r
414         if( !NT_SUCCESS( status ) ) \r
415         {\r
416                 BUS_TRACE_EXIT(BUS_DBG_PNP,\r
417                         ("Getting MLX4 BUS interface failed: status=0x%x\n", status));\r
418                 return STATUS_UNSUCCESSFUL;\r
419         }\r
420         p_ext->hca_ifc_taken = TRUE;\r
421 \r
422         /* bind BFI to HCA by CA GUID. Have to be before ib_register_ca */\r
423         p_bfi->ca_guid = p_ext->hca_ifc.Verbs.guid;\r
424 \r
425         /* register HCA */\r
426         ib_status = ib_register_ca( &p_ext->hca_ifc.Verbs, p_ext->cl_ext.p_pdo, p_dev_obj );\r
427         if( ib_status != IB_SUCCESS )\r
428         {\r
429                 BUS_TRACE_EXIT( BUS_DBG_ERROR, ("ib_register_ca returned %s.\n",\r
430                         ib_get_err_str(ib_status)) );\r
431                 return STATUS_UNSUCCESSFUL;\r
432         }\r
433         BUS_TRACE_EXIT(BUS_DBG_PNP, ("%s bound to CA guid %I64x\n",\r
434                 p_bfi->whoami,p_bfi->ca_guid));\r
435 \r
436         p_ext->ca_registered = TRUE;\r
437         return status;\r
438 }\r
439 \r
440 static NTSTATUS\r
441 fdo_start(\r
442         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
443         IN                                      IRP* const                              p_irp, \r
444                 OUT                             cl_irp_action_t* const  p_action )\r
445 {\r
446         NTSTATUS                status;\r
447         bus_fdo_ext_t   *p_ext;\r
448         ib_api_status_t ib_status;\r
449         bus_filter_t    *p_bfi;\r
450         boolean_t               AL_init_here = FALSE;\r
451 \r
452         BUS_ENTER( BUS_DBG_PNP );\r
453 \r
454         p_ext = p_dev_obj->DeviceExtension;\r
455         p_bfi = p_ext->bus_filter;\r
456         ASSERT( !p_ext->ca_registered );\r
457 \r
458         /* Handled on the way up. */\r
459         status = cl_do_sync_pnp( p_dev_obj, p_irp, p_action );\r
460         if( !NT_SUCCESS( status ) )\r
461         {\r
462                 BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
463                         ("Lower drivers failed IRP_MN_START_DEVICE.\n") );\r
464                 return status;\r
465         }\r
466         p_ext->device_power_state = PowerDeviceD0;\r
467 \r
468         lock_control_event();\r
469         if ( !gp_async_proc_mgr ) {\r
470                 /* Initialize AL */\r
471                 ib_status = al_initialize();\r
472                 if( ib_status != IB_SUCCESS )\r
473                 {\r
474                         al_cleanup();\r
475                         BUS_TRACE_EXIT( BUS_DBG_ERROR, ("al_initialize returned %s.\n",\r
476                                                         ib_get_err_str(ib_status)) );\r
477                         unlock_control_event();\r
478                         return STATUS_UNSUCCESSFUL;\r
479                 }\r
480                 AL_init_here = TRUE;\r
481                 BUS_TRACE( BUS_DBG_PNP, ("AL initialized\n"));\r
482         }\r
483         unlock_control_event();\r
484 \r
485         /* Initialize the port manager. */\r
486         ib_status = create_port_mgr( p_ext->bus_filter );\r
487         if( ib_status != IB_SUCCESS )\r
488         {\r
489                 BUS_TRACE_EXIT( BUS_DBG_ERROR, ("create_port_mgr returned %s.\n",\r
490                         ib_get_err_str(ib_status)) );\r
491                 return STATUS_UNSUCCESSFUL;\r
492         }\r
493 \r
494         /* Initialize the IOU manager. */\r
495         ib_status = create_iou_mgr( p_ext->bus_filter );\r
496         if( ib_status != IB_SUCCESS )\r
497         {\r
498                 BUS_TRACE_EXIT( BUS_DBG_ERROR, ("create_iou_mgr returned %s.\n",\r
499                         ib_get_err_str(ib_status)) );\r
500                 return STATUS_UNSUCCESSFUL;\r
501         }\r
502 \r
503         /* start IBAL */\r
504         status = __register_ca( p_dev_obj );\r
505         if( !NT_SUCCESS( status ) )\r
506                 return status;\r
507 \r
508         if ( AL_init_here ) {\r
509                 status = IoSetDeviceInterfaceState( &al_ifc_name, TRUE );\r
510                 ASSERT( NT_SUCCESS( status ) );\r
511 \r
512                 status = IoSetDeviceInterfaceState( &ci_ifc_name, TRUE );\r
513                 ASSERT( NT_SUCCESS( status ) );\r
514 \r
515                 status = IoSetDeviceInterfaceState( &cm_ifc_name, TRUE );\r
516                 ASSERT( NT_SUCCESS( status ) );\r
517         }\r
518 \r
519         CL_PRINT_TO_EVENT_LOG( p_dev_obj, EVENT_IBBUS_ANY_INFO,\r
520                 ("IBBUS started \n" ));\r
521 \r
522         return status;\r
523 }\r
524 \r
525 \r
526 static NTSTATUS\r
527 fdo_query_remove(\r
528         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
529         IN                                      IRP* const                              p_irp, \r
530                 OUT                             cl_irp_action_t* const  p_action )\r
531 {\r
532         bus_fdo_ext_t   *p_ext;\r
533 \r
534         BUS_ENTER( BUS_DBG_PNP );\r
535 \r
536         p_ext = p_dev_obj->DeviceExtension;\r
537 \r
538         CL_ASSERT(p_ext->bus_filter);\r
539         BUS_PRINT( BUS_DBG_PNP,\r
540                 ("IRP_MN_QUERY_REMOVE_DEVICE %s @ FDO %p refs(CI %d AL %d)\n"\r
541                 "   %s CA %I64x\n", \r
542                 p_ext->cl_ext.vfptr_pnp_po->identity, p_ext, p_ext->n_ci_ifc_ref,\r
543                 p_ext->n_al_ifc_ref,\r
544                 p_ext->bus_filter->whoami, p_ext->bus_filter->ca_guid) );\r
545 \r
546         if( p_ext->n_ci_ifc_ref )\r
547         {\r
548                 /*\r
549                  * Our interface is still being held by someone.\r
550                  * Rollback the PnP state that was changed in the cl_ext handler.\r
551                  */\r
552                 cl_rollback_pnp_state( &p_ext->cl_ext );\r
553 \r
554                 /* Fail the query. */\r
555                 *p_action = IrpComplete;\r
556                 BUS_TRACE_EXIT( BUS_DBG_PNP, \r
557                         ("Failing IRP_MN_QUERY_REMOVE_DEVICE:\n"\r
558                         "\tLowerInterface has %d references\n", \r
559                         p_ext->n_ci_ifc_ref ) );\r
560                 return STATUS_UNSUCCESSFUL;\r
561         }\r
562 \r
563         /* remove port & iou managers */        \r
564         CL_ASSERT( p_ext->bus_filter );\r
565 \r
566         //TODO: Fail outstanding I/O operations.\r
567 \r
568         *p_action = IrpSkip;\r
569         /* The FDO driver must set the status even when passing down. */\r
570         p_irp->IoStatus.Status = STATUS_SUCCESS;\r
571 \r
572         BUS_EXIT( BUS_DBG_PNP );\r
573         return STATUS_SUCCESS;\r
574 }\r
575 \r
576 \r
577 static void\r
578 __deregister_ca(\r
579         IN                                      DEVICE_OBJECT* const    p_dev_obj )\r
580 {\r
581         bus_fdo_ext_t   *p_ext;\r
582         bus_filter_t    *p_bfi;\r
583         ib_api_status_t ib_status;\r
584 \r
585         BUS_ENTER( BUS_DBG_PNP );\r
586 \r
587         p_ext = p_dev_obj->DeviceExtension;\r
588         p_bfi = p_ext->bus_filter;\r
589 \r
590         if ( !p_ext->ca_registered )\r
591                 return;\r
592         p_ext->ca_registered = FALSE;\r
593 \r
594         //TODO: Fail outstanding I/O operations.\r
595 \r
596         ib_status = ib_deregister_ca( p_ext->hca_ifc.Verbs.guid );\r
597         if( ib_status != IB_SUCCESS ) {\r
598                 BUS_PRINT( BUS_DBG_ERROR, ("ib_deregister_ca returned %s.\n",\r
599                         ib_get_err_str(ib_status)) );\r
600         }\r
601 \r
602         if ( p_ext->hca_ifc_taken ) {\r
603                 p_ext->hca_ifc.InterfaceHeader.InterfaceDereference(\r
604                         p_ext->hca_ifc.InterfaceHeader.Context);\r
605                 p_ext->hca_ifc_taken = FALSE;\r
606         }\r
607 \r
608         BUS_EXIT( BUS_DBG_PNP );\r
609 }\r
610 \r
611 /*\r
612  * This function gets called after releasing the remove lock and waiting\r
613  * for all other threads to release the lock.  No more modifications will\r
614  * occur to the PDO pointer vectors.\r
615  */\r
616 static void\r
617 fdo_release_resources(\r
618         IN                                      DEVICE_OBJECT* const    p_dev_obj )\r
619 {\r
620         bus_fdo_ext_t   *p_ext;\r
621         NTSTATUS                status;\r
622         bus_filter_t    *p_bfi;\r
623         int                             ic;\r
624 \r
625         BUS_ENTER( BUS_DBG_PNP );\r
626 \r
627         p_ext = p_dev_obj->DeviceExtension;\r
628         ic = get_bfi_count();\r
629 \r
630         p_bfi = p_ext->bus_filter;\r
631         CL_ASSERT( p_bfi );\r
632 \r
633         __deregister_ca( p_dev_obj );\r
634 \r
635         if ( p_bfi->p_port_mgr )\r
636                 cl_obj_destroy( p_bfi->p_port_mgr_obj );\r
637 \r
638         if ( p_bfi->p_iou_mgr )\r
639                 cl_obj_destroy( p_bfi->p_iou_mgr_obj );\r
640 \r
641 #if 0\r
642         // IBAL has no right to work with CA after it deregister.\r
643         // So there is no need to release interface only after IBAL cleanup\r
644 \r
645         /* if not last HCA then release IFC reference, otherwise release IFC after\r
646          * IBAL has shutdown; keep the HCA present until IBAL is terminated.\r
647          */\r
648         if ( ic > 1 && p_ext->hca_ifc_taken ) {\r
649                 p_ext->hca_ifc.InterfaceHeader.InterfaceDereference(\r
650                         p_ext->hca_ifc.InterfaceHeader.Context);\r
651                 p_ext->hca_ifc_taken = FALSE;\r
652         }\r
653 #endif  \r
654 \r
655         BUS_TRACE( BUS_DBG_PNP, ("Releasing BusFilter %s\n", p_bfi->whoami ));\r
656         if (p_bfi) {\r
657                 p_ext->bus_filter = NULL;\r
658                 p_bfi->p_bus_ext = NULL;\r
659         }\r
660 \r
661         ic = free_bfi( p_bfi );\r
662 \r
663         /* if not last Buf Filter Instance, then exit, otherwise cleanup/shutdown */\r
664         if ( ic > 0 ) {\r
665                 BUS_TRACE_EXIT( BUS_DBG_PNP, ("%d remaining BusFilters\n", ic ));\r
666                 return;\r
667         }\r
668 \r
669         if (g_ControlDeviceObject)\r
670         {\r
671                 IoDeleteSymbolicLink( &g_CDO_dos_name );\r
672                 IoDeleteDevice(g_ControlDeviceObject);\r
673                 g_ControlDeviceObject = NULL; \r
674         }\r
675 \r
676         /* Disable any exported interfaces. */\r
677         status = IoSetDeviceInterfaceState( &al_ifc_name, FALSE );\r
678         ASSERT( NT_SUCCESS( status ) );\r
679         status = IoSetDeviceInterfaceState( &ci_ifc_name, FALSE );\r
680         ASSERT( NT_SUCCESS( status ) );\r
681         status = IoSetDeviceInterfaceState( &cm_ifc_name, FALSE );\r
682         ASSERT( NT_SUCCESS( status ) );\r
683 \r
684         /* Release the memory allocated for the interface symbolic names. */\r
685         RtlFreeUnicodeString( &cm_ifc_name );\r
686         RtlFreeUnicodeString( &ci_ifc_name );\r
687         RtlFreeUnicodeString( &al_ifc_name );\r
688 \r
689         al_cleanup();\r
690         cl_thread_suspend(50);  /* allow time for AL's async procs to run to exit */\r
691 \r
692         CL_ASSERT( !gp_async_proc_mgr && !gp_async_pnp_mgr && !gp_al_mgr );\r
693 \r
694 #if 0\r
695                 // IBAL has no right to work with CA after it deregister.\r
696                 // So there is no need to release interface only after IBAL cleanup\r
697         \r
698         /* AL needs the HCA to stick around until AL cleanup has completed.\r
699          * Now that it's done, let the HCA fade away.\r
700          */\r
701         if ( p_ext->hca_ifc_taken ) {\r
702                 p_ext->hca_ifc.InterfaceHeader.InterfaceDereference(\r
703                         p_ext->hca_ifc.InterfaceHeader.Context);\r
704                 p_ext->hca_ifc_taken = FALSE;\r
705         }\r
706 #endif  \r
707 \r
708         BUS_EXIT( BUS_DBG_PNP );\r
709 }\r
710 \r
711 \r
712 static NTSTATUS\r
713 fdo_query_capabilities(\r
714         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
715         IN                                      IRP* const                              p_irp, \r
716                 OUT                             cl_irp_action_t* const  p_action )\r
717 {\r
718         NTSTATUS                        status;\r
719         bus_fdo_ext_t           *p_ext;\r
720         IO_STACK_LOCATION       *p_io_stack;\r
721 \r
722         BUS_ENTER( BUS_DBG_PNP );\r
723 \r
724         p_ext = p_dev_obj->DeviceExtension;\r
725 \r
726         /* Process on the way up. */\r
727         status = cl_do_sync_pnp( p_dev_obj, p_irp, p_action );\r
728 \r
729         if( !NT_SUCCESS( status ) )\r
730         {\r
731                 BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
732                         ("cl_do_sync_pnp returned %08x.\n", status) );\r
733                 return status;\r
734         }\r
735 \r
736         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
737 \r
738         /*\r
739          * Store the device power maping into our extension since we're\r
740          * the power policy owner.  The mapping is used when handling\r
741          * IRP_MN_SET_POWER IRPs.\r
742          */\r
743         cl_memcpy( p_ext->po_state, \r
744                 p_io_stack->Parameters.DeviceCapabilities.Capabilities->DeviceState,\r
745                 sizeof( p_ext->po_state ) );\r
746 \r
747         BUS_EXIT( BUS_DBG_PNP );\r
748         return status;\r
749 }\r
750 \r
751 \r
752 static NTSTATUS\r
753 fdo_query_bus_relations(\r
754         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
755         IN                                      IRP* const                              p_irp, \r
756                 OUT                             cl_irp_action_t* const  p_action )\r
757 {\r
758         NTSTATUS                        status = STATUS_SUCCESS; /*default to success*/\r
759         bus_fdo_ext_t           *p_ext;\r
760         bus_filter_t            *p_bfi;\r
761         int                                     waitLoop = 0;\r
762 \r
763         BUS_ENTER( BUS_DBG_PNP );\r
764 \r
765         p_ext = p_dev_obj->DeviceExtension;\r
766 \r
767         if ( !p_ext->bus_filter )\r
768         {\r
769                 /* BFI has already been released */\r
770                 *p_action = IrpComplete;\r
771                 BUS_TRACE_EXIT( BUS_DBG_PNP, ("NULL BFI\n") );\r
772                 return STATUS_SUCCESS;\r
773         }\r
774 \r
775         p_bfi = p_ext->bus_filter;\r
776         CL_ASSERT( p_bfi->magic == BFI_MAGIC );\r
777 \r
778         while ( p_bfi->ca_guid == 0ULL )\r
779         {\r
780                 /* HCA not yet bound to a BFI slot (no PNP ADD event seen), no bus\r
781                  * relations yet.\r
782                  */\r
783                 BUS_PRINT(BUS_DBG_ERROR, ("%s ca_guid %I64x\n",p_bfi->whoami,\r
784                                                                 p_bfi->ca_guid));\r
785                 cl_thread_suspend( 100 );       /* suspend for 100 ms */\r
786                 waitLoop++;\r
787                 if(waitLoop>50) break;\r
788         }\r
789         if ( p_bfi->ca_guid != 0ULL )\r
790         {\r
791                 status = port_mgr_get_bus_relations( p_bfi->ca_guid, p_irp );\r
792                 if( status == STATUS_SUCCESS || \r
793                         status == STATUS_NO_SUCH_DEVICE )\r
794                 {\r
795                         status = iou_mgr_get_bus_relations( p_bfi->ca_guid, p_irp );\r
796                 }\r
797                 if( status == STATUS_NO_SUCH_DEVICE )\r
798                         status = STATUS_SUCCESS;\r
799         }\r
800 \r
801         switch( status )\r
802         {\r
803         case STATUS_NO_SUCH_DEVICE:\r
804                 *p_action = IrpSkip;\r
805                 status = STATUS_SUCCESS;\r
806                 break;\r
807 \r
808         case STATUS_SUCCESS:\r
809                 *p_action = IrpPassDown;\r
810                 break;\r
811 \r
812         default:\r
813                 *p_action = IrpComplete;\r
814                 break;\r
815         }\r
816 \r
817         BUS_EXIT( BUS_DBG_PNP );\r
818         return status;\r
819 }\r
820 \r
821 \r
822 void\r
823 al_ref_ifc(\r
824         IN                              DEVICE_OBJECT*                          p_dev_obj )\r
825 {\r
826         bus_fdo_ext_t   *p_ext;\r
827 \r
828         BUS_ENTER( BUS_DBG_PNP );\r
829 \r
830         p_ext = p_dev_obj->DeviceExtension;\r
831 \r
832         CL_ASSERT( p_ext->n_al_ifc_ref >= 0 );\r
833 \r
834         cl_atomic_inc( &p_ext->n_al_ifc_ref );\r
835         ObReferenceObject( p_dev_obj );\r
836 \r
837         BUS_EXIT( BUS_DBG_PNP );\r
838 }\r
839 \r
840 \r
841 void\r
842 al_deref_ifc(\r
843         IN                              DEVICE_OBJECT*                          p_dev_obj )\r
844 {\r
845         bus_fdo_ext_t   *p_ext;\r
846 \r
847         BUS_ENTER( BUS_DBG_PNP );\r
848 \r
849         p_ext = p_dev_obj->DeviceExtension;\r
850 \r
851         CL_ASSERT( p_ext->n_al_ifc_ref > 0 );\r
852         cl_atomic_dec( &p_ext->n_al_ifc_ref );\r
853         ObDereferenceObject( p_dev_obj );\r
854 \r
855         BUS_EXIT( BUS_DBG_PNP );\r
856 }\r
857 \r
858 \r
859 void\r
860 al_ref_ci_ifc(\r
861         IN                              DEVICE_OBJECT*                          p_dev_obj )\r
862 {\r
863         bus_fdo_ext_t   *p_ext;\r
864 \r
865         BUS_ENTER( BUS_DBG_PNP );\r
866 \r
867         p_ext = p_dev_obj->DeviceExtension;\r
868 \r
869         CL_ASSERT( p_ext->n_ci_ifc_ref >= 0 );\r
870         cl_atomic_inc( &p_ext->n_ci_ifc_ref );\r
871         ObReferenceObject( p_dev_obj );\r
872 \r
873         BUS_EXIT( BUS_DBG_PNP );\r
874 }\r
875 \r
876 \r
877 void\r
878 al_deref_ci_ifc(\r
879         IN                              DEVICE_OBJECT*                          p_dev_obj )\r
880 {\r
881         bus_fdo_ext_t   *p_ext;\r
882 \r
883         BUS_ENTER( BUS_DBG_PNP );\r
884 \r
885         p_ext = p_dev_obj->DeviceExtension;\r
886 \r
887         CL_ASSERT( p_ext->n_ci_ifc_ref > 0 );\r
888 \r
889         cl_atomic_dec( &p_ext->n_ci_ifc_ref );\r
890         ObDereferenceObject( p_dev_obj );\r
891 \r
892 \r
893         BUS_EXIT( BUS_DBG_PNP );\r
894 }\r
895 \r
896 \r
897 static NTSTATUS\r
898 __query_al_ifc(\r
899         IN                                      DEVICE_OBJECT* const            p_dev_obj,\r
900         IN                                      IO_STACK_LOCATION* const        p_io_stack )\r
901 {\r
902         ib_al_ifc_t             *p_ifc;\r
903 \r
904         BUS_ENTER( BUS_DBG_PNP );\r
905 \r
906         if( p_io_stack->Parameters.QueryInterface.Version != \r
907                 AL_INTERFACE_VERSION )\r
908         {\r
909                 BUS_TRACE_EXIT( BUS_DBG_PNP, ("Incorrect interface version (%d)\n",\r
910                         p_io_stack->Parameters.QueryInterface.Version ) );\r
911                 return STATUS_NOT_SUPPORTED;\r
912         }\r
913 \r
914         if( p_io_stack->Parameters.QueryInterface.Size < sizeof(ib_al_ifc_t) )\r
915         {\r
916                 BUS_TRACE_EXIT( BUS_DBG_PNP, \r
917                         ("Buffer too small (%d given, %d required).\n",\r
918                         p_io_stack->Parameters.QueryInterface.Size, sizeof(ib_al_ifc_t)) );\r
919                 return STATUS_BUFFER_TOO_SMALL;\r
920         }\r
921 \r
922         // Copy the interface.\r
923         p_ifc = (ib_al_ifc_t*)p_io_stack->Parameters.QueryInterface.Interface;\r
924 \r
925         p_ifc->wdm.Size = sizeof(ib_al_ifc_t);\r
926         p_ifc->wdm.Version = AL_INTERFACE_VERSION;\r
927         p_ifc->wdm.Context = p_dev_obj;\r
928         p_ifc->wdm.InterfaceReference = al_ref_ifc;\r
929         p_ifc->wdm.InterfaceDereference = al_deref_ifc;\r
930 \r
931         __set_ifc( p_ifc );\r
932 \r
933         // take the reference before returning.\r
934         al_ref_ifc( p_dev_obj );\r
935         BUS_EXIT( BUS_DBG_PNP );\r
936         return STATUS_SUCCESS;\r
937 }\r
938 \r
939 static void\r
940 __set_ifc(\r
941                 OUT                     ib_al_ifc_t* const                      p_ifc )\r
942 {\r
943         BUS_ENTER( BUS_DBG_PNP );\r
944 \r
945         p_ifc->wdm.Size = sizeof(ib_al_ifc_t);\r
946         p_ifc->wdm.InterfaceReference = al_ref_ifc;\r
947         p_ifc->wdm.InterfaceDereference = al_deref_ifc;\r
948 \r
949         p_ifc->sync_destroy = ib_sync_destroy;\r
950         p_ifc->open_ca = ib_open_ca;\r
951         p_ifc->query_ca = ib_query_ca;\r
952         p_ifc->get_dev = get_ca_dev;\r
953         p_ifc->close_ca = ib_close_ca;\r
954         p_ifc->alloc_pd = ib_alloc_pd;\r
955         p_ifc->dealloc_pd = ib_dealloc_pd;\r
956         p_ifc->create_av = ib_create_av;\r
957         p_ifc->query_av = ib_query_av;\r
958         p_ifc->modify_av = ib_modify_av;\r
959         p_ifc->destroy_av = ib_destroy_av;\r
960         p_ifc->create_qp = ib_create_qp;\r
961         p_ifc->get_spl_qp = ib_get_spl_qp;\r
962         p_ifc->query_qp = ib_query_qp;\r
963         p_ifc->modify_qp = ib_modify_qp;\r
964         p_ifc->destroy_qp = ib_destroy_qp;\r
965         p_ifc->create_cq = ib_create_cq;\r
966         p_ifc->modify_cq = ib_modify_cq;\r
967         p_ifc->query_cq = ib_query_cq;\r
968         p_ifc->destroy_cq = ib_destroy_cq;\r
969         p_ifc->reg_mem = ib_reg_mem;\r
970         p_ifc->reg_phys = ib_reg_phys;\r
971         p_ifc->query_mr = ib_query_mr;\r
972         p_ifc->rereg_mem = ib_rereg_mem;\r
973         p_ifc->reg_shmid = ib_reg_shmid;\r
974         p_ifc->dereg_mr = ib_dereg_mr;\r
975         p_ifc->create_mw = ib_create_mw;\r
976         p_ifc->query_mw = ib_query_mw;\r
977         p_ifc->bind_mw = ib_bind_mw;\r
978         p_ifc->destroy_mw = ib_destroy_mw;\r
979         p_ifc->post_send = ib_post_send;\r
980         p_ifc->post_recv = ib_post_recv;\r
981         p_ifc->send_mad = ib_send_mad;\r
982         p_ifc->cancel_mad = ib_cancel_mad;\r
983         p_ifc->poll_cq = ib_poll_cq;\r
984         p_ifc->rearm_cq = ib_rearm_cq;\r
985         p_ifc->join_mcast = ib_join_mcast;\r
986         p_ifc->leave_mcast = ib_leave_mcast;\r
987         p_ifc->local_mad = ib_local_mad;\r
988         p_ifc->cm_listen = ib_cm_listen;\r
989         p_ifc->cm_cancel = ib_cm_cancel;\r
990         p_ifc->cm_req = ib_cm_req;\r
991         p_ifc->cm_rep = ib_cm_rep;\r
992         p_ifc->cm_rtu = ib_cm_rtu;\r
993         p_ifc->cm_rej = ib_cm_rej;\r
994         p_ifc->cm_mra = ib_cm_mra;\r
995         p_ifc->cm_lap = ib_cm_lap;\r
996         p_ifc->cm_apr = ib_cm_apr;\r
997         p_ifc->force_apm = ib_force_apm;\r
998         p_ifc->cm_dreq = ib_cm_dreq;\r
999         p_ifc->cm_drep = ib_cm_drep;\r
1000         p_ifc->cm_handoff = ib_cm_handoff;\r
1001         p_ifc->create_ioc = ib_create_ioc;\r
1002         p_ifc->destroy_ioc = ib_destroy_ioc;\r
1003         p_ifc->reg_ioc = ib_reg_ioc;\r
1004         p_ifc->add_svc_entry = ib_add_svc_entry;\r
1005         p_ifc->remove_svc_entry = ib_remove_svc_entry;\r
1006         p_ifc->get_ca_guids = ib_get_ca_guids;\r
1007         p_ifc->get_ca_by_gid = ib_get_ca_by_gid;\r
1008         p_ifc->get_port_by_gid = ib_get_port_by_gid;\r
1009         p_ifc->create_mad_pool = ib_create_mad_pool;\r
1010         p_ifc->destroy_mad_pool = ib_destroy_mad_pool;\r
1011         p_ifc->reg_mad_pool = ib_reg_mad_pool;\r
1012         p_ifc->dereg_mad_pool = ib_dereg_mad_pool;\r
1013         p_ifc->get_mad = ib_get_mad;\r
1014         p_ifc->put_mad = ib_put_mad;\r
1015         p_ifc->init_dgrm_svc = ib_init_dgrm_svc;\r
1016         p_ifc->reg_mad_svc = ib_reg_mad_svc;\r
1017         p_ifc->reg_svc = ib_reg_svc;\r
1018         p_ifc->dereg_svc = ib_dereg_svc;\r
1019         p_ifc->query = ib_query;\r
1020         p_ifc->cancel_query = ib_cancel_query;\r
1021         p_ifc->reg_pnp = ib_reg_pnp;\r
1022         p_ifc->dereg_pnp = ib_dereg_pnp;\r
1023         p_ifc->subscribe = ib_subscribe;\r
1024         p_ifc->unsubscribe = ib_unsubscribe;\r
1025         p_ifc->reject_ioc = ib_reject_ioc;\r
1026         p_ifc->ci_call = ib_ci_call;\r
1027         p_ifc->open_al = ib_open_al;\r
1028         p_ifc->close_al = ib_close_al;\r
1029         p_ifc->get_err_str = ib_get_err_str;\r
1030         p_ifc->get_wc_status_str = ib_get_wc_status_str;\r
1031         p_ifc->create_mlnx_fmr = mlnx_create_fmr;\r
1032         p_ifc->map_phys_mlnx_fmr = mlnx_map_phys_fmr;\r
1033         p_ifc->unmap_mlnx_fmr = mlnx_unmap_fmr;\r
1034         p_ifc->destroy_mlnx_fmr = mlnx_destroy_fmr;\r
1035         p_ifc->create_mlnx_fmr_pool = mlnx_create_fmr_pool;\r
1036         p_ifc->destroy_mlnx_fmr_pool = mlnx_destroy_fmr_pool;\r
1037         p_ifc->map_phys_mlnx_fmr_pool = mlnx_map_phys_fmr_pool;\r
1038         p_ifc->unmap_mlnx_fmr_pool = mlnx_unmap_fmr_pool;\r
1039         p_ifc->flush_mlnx_fmr_pool = mlnx_flush_fmr_pool;\r
1040         p_ifc->create_srq = ib_create_srq;\r
1041         p_ifc->modify_srq = ib_modify_srq;\r
1042         p_ifc->query_srq = ib_query_srq;\r
1043         p_ifc->destroy_srq = ib_destroy_srq;\r
1044         p_ifc->post_srq_recv = ib_post_srq_recv;\r
1045 \r
1046         BUS_EXIT( BUS_DBG_PNP );\r
1047 }\r
1048 \r
1049 \r
1050 static NTSTATUS\r
1051 __get_relations(\r
1052         IN              const   net64_t                                         ca_guid,\r
1053         IN                              IRP* const                                      p_irp )\r
1054 {\r
1055         UNUSED_PARAM( ca_guid );\r
1056         UNUSED_PARAM( p_irp );\r
1057 \r
1058         BUS_ENTER( BUS_DBG_PNP );\r
1059 \r
1060         /*\r
1061          * Now that ibbus is in the same device stack as the HCA driver, skip\r
1062          * returning relations here as ibbus has already done the deed.\r
1063          * This interface remains to minimize changes to HCA drivers for now.\r
1064          */\r
1065 \r
1066         BUS_EXIT( BUS_DBG_PNP );\r
1067         return STATUS_SUCCESS;\r
1068 }\r
1069 \r
1070 \r
1071 static NTSTATUS\r
1072 __query_ci_ifc(\r
1073         IN                                      DEVICE_OBJECT* const            p_dev_obj,\r
1074         IN                                      IO_STACK_LOCATION* const        p_io_stack )\r
1075 {\r
1076         ib_ci_ifc_t             *p_ifc;\r
1077 \r
1078         BUS_ENTER( BUS_DBG_PNP );\r
1079 \r
1080         if( p_io_stack->Parameters.QueryInterface.Version != \r
1081                 IB_CI_INTERFACE_VERSION )\r
1082         {\r
1083                 BUS_TRACE_EXIT( BUS_DBG_PNP, ("Incorrect interface version (%d)\n",\r
1084                         p_io_stack->Parameters.QueryInterface.Version ) );\r
1085                 return STATUS_NOT_SUPPORTED;\r
1086         }\r
1087 \r
1088         if( p_io_stack->Parameters.QueryInterface.Size < sizeof(ib_ci_ifc_t) )\r
1089         {\r
1090                 BUS_TRACE_EXIT( BUS_DBG_PNP, \r
1091                         ("Buffer too small (%d given, %d required).\n",\r
1092                         p_io_stack->Parameters.QueryInterface.Size, sizeof(ib_ci_ifc_t)) );\r
1093                 return STATUS_BUFFER_TOO_SMALL;\r
1094         }\r
1095 \r
1096         /* Copy the interface. */\r
1097         p_ifc = (ib_ci_ifc_t*)p_io_stack->Parameters.QueryInterface.Interface;\r
1098 \r
1099         p_ifc->wdm.Size = sizeof(ib_ci_ifc_t);\r
1100         p_ifc->wdm.Version = IB_CI_INTERFACE_VERSION;\r
1101         p_ifc->wdm.Context = p_dev_obj;\r
1102         p_ifc->wdm.InterfaceReference = al_ref_ci_ifc;\r
1103         p_ifc->wdm.InterfaceDereference = al_deref_ci_ifc;\r
1104 \r
1105         /* Set the entry points. */\r
1106         p_ifc->register_ca = ib_register_ca;\r
1107         p_ifc->deregister_ca = ib_deregister_ca;\r
1108         p_ifc->get_relations = __get_relations;\r
1109         p_ifc->get_err_str = ib_get_err_str;\r
1110 \r
1111         /* take the reference before returning. */\r
1112         al_ref_ci_ifc( p_dev_obj );\r
1113         BUS_EXIT( BUS_DBG_PNP );\r
1114         return STATUS_SUCCESS;\r
1115 }\r
1116 \r
1117 \r
1118 static NTSTATUS\r
1119 __query_cm_ifc(\r
1120         IN                                      DEVICE_OBJECT* const            p_dev_obj,\r
1121         IN                                      IO_STACK_LOCATION* const        p_io_stack )\r
1122 {\r
1123         INFINIBAND_INTERFACE_CM *p_ifc;\r
1124 \r
1125         BUS_ENTER( BUS_DBG_PNP );\r
1126 \r
1127         if( p_io_stack->Parameters.QueryInterface.Version != IbaCmVersion(1, 0) )\r
1128         {\r
1129                 BUS_TRACE_EXIT( BUS_DBG_PNP, ("Incorrect interface version (%d)\n",\r
1130                         p_io_stack->Parameters.QueryInterface.Version ) );\r
1131                 return STATUS_NOT_SUPPORTED;\r
1132         }\r
1133 \r
1134         if( p_io_stack->Parameters.QueryInterface.Size < sizeof(INFINIBAND_INTERFACE_CM) )\r
1135         {\r
1136                 BUS_TRACE_EXIT( BUS_DBG_PNP, \r
1137                         ("Buffer too small (%d given, %d required).\n",\r
1138                         p_io_stack->Parameters.QueryInterface.Size, sizeof(INFINIBAND_INTERFACE_CM)) );\r
1139                 return STATUS_BUFFER_TOO_SMALL;\r
1140         }\r
1141 \r
1142         /* Copy the interface. */\r
1143         p_ifc = (INFINIBAND_INTERFACE_CM*)p_io_stack->Parameters.QueryInterface.Interface;\r
1144 \r
1145         p_ifc->InterfaceHeader.Size = sizeof(INFINIBAND_INTERFACE_CM);\r
1146         p_ifc->InterfaceHeader.Version = IbaCmVersion(1, 0);\r
1147         p_ifc->InterfaceHeader.Context = p_dev_obj;\r
1148         p_ifc->InterfaceHeader.InterfaceReference = al_ref_ifc;\r
1149         p_ifc->InterfaceHeader.InterfaceDereference = al_deref_ifc;\r
1150         cm_get_interface(&p_ifc->CM);\r
1151 \r
1152         /* take the reference before returning. */\r
1153         al_ref_ifc( p_dev_obj );\r
1154         BUS_EXIT( BUS_DBG_PNP );\r
1155         return STATUS_SUCCESS;\r
1156 }\r
1157 \r
1158 static NTSTATUS\r
1159 fdo_query_pnp_state(\r
1160         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1161         IN                              IRP* const                                      p_irp, \r
1162                 OUT                     cl_irp_action_t* const          p_action )\r
1163 {\r
1164         bus_fdo_ext_t           *p_ext;\r
1165 \r
1166         BUS_ENTER( BUS_DBG_PNP );\r
1167 \r
1168         p_ext = (bus_fdo_ext_t*)p_dev_obj->DeviceExtension;\r
1169 \r
1170         p_irp->IoStatus.Information |= p_ext->pnp_state;\r
1171 \r
1172         *p_action = IrpSkip;\r
1173 \r
1174         BUS_EXIT( BUS_DBG_PNP );\r
1175         return STATUS_SUCCESS;;\r
1176 }\r
1177 \r
1178 \r
1179 static NTSTATUS\r
1180 fdo_query_interface(\r
1181         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
1182         IN                                      IRP* const                              p_irp, \r
1183                 OUT                             cl_irp_action_t* const  p_action )\r
1184 {\r
1185         NTSTATUS                        status;\r
1186         IO_STACK_LOCATION       *p_io_stack;\r
1187 \r
1188         BUS_ENTER( BUS_DBG_PNP );\r
1189 \r
1190         PAGED_CODE();\r
1191 \r
1192         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
1193         \r
1194         /* Compare requested GUID with our supported interface GUIDs. */\r
1195         if( IsEqualGUID( p_io_stack->Parameters.QueryInterface.InterfaceType,\r
1196                 &GUID_IB_AL_INTERFACE ) )\r
1197         {\r
1198                 status = __query_al_ifc( p_dev_obj, p_io_stack );\r
1199         }\r
1200         else if( IsEqualGUID( p_io_stack->Parameters.QueryInterface.InterfaceType,\r
1201                 &GUID_IB_CI_INTERFACE ) )\r
1202         {\r
1203                 status = __query_ci_ifc( p_dev_obj, p_io_stack );\r
1204         }\r
1205         else if( IsEqualGUID( p_io_stack->Parameters.QueryInterface.InterfaceType,\r
1206                 &GUID_INFINIBAND_INTERFACE_CM ) )\r
1207         {\r
1208                 status = __query_cm_ifc( p_dev_obj, p_io_stack );\r
1209         }\r
1210         else\r
1211         {\r
1212                 status = p_irp->IoStatus.Status;\r
1213         }\r
1214 \r
1215         if( NT_SUCCESS( status ) )\r
1216                 *p_action = IrpSkip;\r
1217         else if( status == STATUS_BUFFER_TOO_SMALL )\r
1218                 *p_action = IrpComplete;\r
1219         else\r
1220                 *p_action = IrpIgnore;\r
1221 \r
1222         BUS_EXIT( BUS_DBG_PNP );\r
1223         return status;\r
1224 }\r
1225 \r
1226 \r
1227 static NTSTATUS\r
1228 __fdo_query_power(\r
1229         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1230         IN                              IRP* const                                      p_irp,\r
1231                 OUT                     cl_irp_action_t* const          p_action )\r
1232 {\r
1233         NTSTATUS                        status = STATUS_SUCCESS;\r
1234         IO_STACK_LOCATION       *p_io_stack;\r
1235 \r
1236         BUS_ENTER( BUS_DBG_POWER );\r
1237 \r
1238         UNUSED_PARAM( p_dev_obj );\r
1239 \r
1240         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
1241 \r
1242         switch( p_io_stack->Parameters.Power.Type )\r
1243         {\r
1244         case SystemPowerState:\r
1245                 /* Fail any requests to hibernate or sleep the system. */\r
1246                 switch( p_io_stack->Parameters.Power.State.SystemState )\r
1247                 {\r
1248                         case PowerSystemHibernate:\r
1249                         case PowerSystemSleeping1:      // STANDBY support\r
1250                         case PowerSystemSleeping2:      // STANDBY support\r
1251                         case PowerSystemSleeping3:      // STANDBY support\r
1252                         case PowerSystemWorking:\r
1253                         case PowerSystemShutdown:\r
1254                                 break;\r
1255 \r
1256                         default:\r
1257                                 status = STATUS_NOT_SUPPORTED;\r
1258                 }\r
1259                 break;\r
1260 \r
1261         case DevicePowerState:\r
1262                 /* Fail any query for low power states. */\r
1263                 switch( p_io_stack->Parameters.Power.State.DeviceState )\r
1264                 {\r
1265                 case PowerDeviceD0:\r
1266                 case PowerDeviceD3:\r
1267                         /* We only support fully powered or off power states. */\r
1268                         break;\r
1269 \r
1270                 default:\r
1271                         status = STATUS_NOT_SUPPORTED;\r
1272                 }\r
1273                 break;\r
1274         }\r
1275 \r
1276         if( status == STATUS_NOT_SUPPORTED )\r
1277                 *p_action = IrpComplete;\r
1278         else\r
1279                 *p_action = IrpSkip;\r
1280 \r
1281         BUS_EXIT( BUS_DBG_POWER );\r
1282         return status;\r
1283 }\r
1284 \r
1285 \r
1286 \r
1287 /* Work item callback to handle DevicePowerD0 IRPs at passive level. */\r
1288 \r
1289 static void\r
1290 __device_power_up_completion_workItem(\r
1291         IN                              DEVICE_OBJECT*                          p_dev_obj,\r
1292         IN                              void*                                           context )\r
1293 {\r
1294         NTSTATUS                        status;\r
1295         IO_STACK_LOCATION       *p_io_stack;\r
1296         bus_fdo_ext_t           *p_ext;\r
1297         IRP                                     *p_irp;\r
1298         POWER_STATE                     power_state;\r
1299 \r
1300         BUS_ENTER( BUS_DBG_POWER );\r
1301 \r
1302         p_ext = (bus_fdo_ext_t*)p_dev_obj->DeviceExtension;\r
1303         p_irp = (IRP*)context;\r
1304         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
1305 \r
1306         IoFreeWorkItem( p_ext->p_po_work_item );\r
1307         p_ext->p_po_work_item = NULL;\r
1308 \r
1309         /* re-register CA */\r
1310         BUS_PRINT( BUS_DBG_POWER, \r
1311                 ("***** re-register CA, IRQL %d\n", KeGetCurrentIrql()));\r
1312 \r
1313         status = __register_ca( p_dev_obj );\r
1314         if( !NT_SUCCESS( status ) ) {\r
1315                 BUS_PRINT( BUS_DBG_POWER, \r
1316                         ("!!! __register_ca failed (%#x) \n", status));\r
1317                 goto err_fdo_start;\r
1318         }\r
1319 \r
1320         p_ext->device_power_state = p_io_stack->Parameters.Power.State.DeviceState;\r
1321         power_state = PoSetPowerState( p_dev_obj, DevicePowerState,\r
1322                 p_io_stack->Parameters.Power.State );\r
1323 \r
1324         BUS_PRINT( BUS_DBG_POWER, \r
1325                 ("PoSetPowerState: old state %d, new state to %d\n", \r
1326                 power_state.DeviceState, p_ext->device_power_state ));\r
1327 \r
1328         CL_PRINT_TO_EVENT_LOG( p_dev_obj, EVENT_IBBUS_ANY_WARN,\r
1329                 ("Power increased to: device %d, system %d.\n",\r
1330                 (int)p_ext->device_power_state, (int)p_ext->system_power_state));\r
1331 \r
1332         goto exit;\r
1333 \r
1334 err_fdo_start:\r
1335         /* Flag device as having failed. */\r
1336         p_ext->pnp_state |= PNP_DEVICE_FAILED;\r
1337         IoInvalidateDeviceState( p_ext->cl_ext.p_pdo );\r
1338 exit:\r
1339         PoStartNextPowerIrp( p_irp );\r
1340         IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
1341         IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
1342         BUS_EXIT( BUS_DBG_POWER );\r
1343 }\r
1344 \r
1345 \r
1346 /*NOTE: Completion routines must NEVER be pageable. */\r
1347 static NTSTATUS\r
1348 __device_power_up_completion(\r
1349         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
1350         IN                              IRP                                                     *p_irp,\r
1351         IN                              void                                            *context )\r
1352 {\r
1353         NTSTATUS                        status = STATUS_SUCCESS;\r
1354         bus_fdo_ext_t           *p_ext;\r
1355         IO_STACK_LOCATION       *p_io_stack;\r
1356 \r
1357         BUS_ENTER( BUS_DBG_POWER );\r
1358 \r
1359         UNUSED_PARAM( context );\r
1360 \r
1361         p_ext = (bus_fdo_ext_t*)p_dev_obj->DeviceExtension;\r
1362         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
1363 \r
1364         if( !NT_SUCCESS( p_irp->IoStatus.Status ) ) {\r
1365                 BUS_PRINT( BUS_DBG_POWER, \r
1366                         ("IRP_MN_SET_POWER for device failed by lower driver with %08x.\n",\r
1367                         p_irp->IoStatus.Status));\r
1368                 status =  STATUS_SUCCESS;\r
1369                 PoStartNextPowerIrp( p_irp );\r
1370                 goto release;\r
1371         }\r
1372 \r
1373         /* Process in a work item to allow blocking. */\r
1374         ASSERT( !p_ext->p_po_work_item );\r
1375         p_ext->p_po_work_item = IoAllocateWorkItem( p_dev_obj );\r
1376         if( !p_ext->p_po_work_item ) {\r
1377                 BUS_PRINT( BUS_DBG_POWER, \r
1378                         ("Failed to allocate work item.\n" ));\r
1379                 status = STATUS_SUCCESS;\r
1380                 p_ext->pnp_state |= PNP_DEVICE_FAILED;\r
1381                 IoInvalidateDeviceState( p_ext->cl_ext.p_pdo );\r
1382                 PoStartNextPowerIrp( p_irp );\r
1383                 goto release;\r
1384         }\r
1385 \r
1386         /* Process in work item callback. */\r
1387         IoMarkIrpPending( p_irp );\r
1388         IoQueueWorkItem( p_ext->p_po_work_item, \r
1389                 __device_power_up_completion_workItem, DelayedWorkQueue, p_irp );\r
1390         status = STATUS_MORE_PROCESSING_REQUIRED;\r
1391         goto exit;\r
1392 \r
1393 release:        \r
1394         IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
1395 exit:   \r
1396         BUS_EXIT( BUS_DBG_POWER );\r
1397         return status;\r
1398 }\r
1399 \r
1400 \r
1401 static NTSTATUS __device_power_down_workItem_completion(\r
1402         IN                              DEVICE_OBJECT   *p_dev_obj,\r
1403         IN                              IRP                             *p_irp,\r
1404         IN                              void                            *context )\r
1405 {\r
1406         bus_fdo_ext_t           *p_ext = (bus_fdo_ext_t*)p_dev_obj->DeviceExtension;\r
1407         UNUSED_PARAM( context );\r
1408 \r
1409         BUS_ENTER( BUS_DBG_POWER );\r
1410 \r
1411         PoStartNextPowerIrp( p_irp );\r
1412         IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
1413 \r
1414         BUS_EXIT( BUS_DBG_POWER );\r
1415         return STATUS_SUCCESS;\r
1416 }\r
1417 \r
1418 /* Work item callback to handle DevicePowerD3 IRPs at passive level. */\r
1419 static void\r
1420 __device_power_down_workItem(\r
1421         IN                              DEVICE_OBJECT*                          p_dev_obj,\r
1422         IN                              void*                                           context )\r
1423 {\r
1424         IO_STACK_LOCATION       *p_io_stack;\r
1425         bus_fdo_ext_t           *p_ext;\r
1426         IRP                                     *p_irp;\r
1427         POWER_STATE                     power_state;\r
1428 \r
1429         BUS_ENTER( BUS_DBG_POWER );\r
1430 \r
1431         p_ext = (bus_fdo_ext_t*)p_dev_obj->DeviceExtension;\r
1432         p_irp = (IRP*)context;\r
1433         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
1434 \r
1435         IoFreeWorkItem( p_ext->p_po_work_item );\r
1436         p_ext->p_po_work_item = NULL;\r
1437 \r
1438         p_ext->device_power_state = p_io_stack->Parameters.Power.State.DeviceState;\r
1439         power_state = PoSetPowerState( p_dev_obj, DevicePowerState,\r
1440                 p_io_stack->Parameters.Power.State );\r
1441 \r
1442         BUS_PRINT( BUS_DBG_POWER, \r
1443                 ("PoSetPowerState: old state %d, new state to %d, IRQL %d\n", \r
1444                 power_state.DeviceState, p_ext->device_power_state, KeGetCurrentIrql() ));\r
1445 \r
1446         CL_PRINT_TO_EVENT_LOG( p_dev_obj, EVENT_IBBUS_ANY_WARN,\r
1447                 ("Power decreased to: device %d, system %d.\n",\r
1448                 (int)p_ext->device_power_state, (int)p_ext->system_power_state));\r
1449 \r
1450         BUS_PRINT( BUS_DBG_POWER, \r
1451                 ("***** deregister CA \n"));\r
1452 \r
1453         __deregister_ca( p_dev_obj );\r
1454 \r
1455         IoCopyCurrentIrpStackLocationToNext( p_irp );\r
1456 #pragma warning( push, 3 )\r
1457         IoSetCompletionRoutine( p_irp, __device_power_down_workItem_completion,\r
1458                 NULL, TRUE, TRUE, TRUE );\r
1459 #pragma warning( pop )\r
1460         PoCallDriver( p_ext->cl_ext.p_next_do, p_irp );\r
1461 \r
1462         BUS_EXIT( BUS_DBG_POWER );\r
1463 }\r
1464 \r
1465 \r
1466 \r
1467 static NTSTATUS\r
1468 __fdo_set_power(\r
1469         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1470         IN                              IRP* const                                      p_irp,\r
1471                 OUT                     cl_irp_action_t* const          p_action )\r
1472 {\r
1473         NTSTATUS                        status;\r
1474         IO_STACK_LOCATION       *p_io_stack;\r
1475         bus_fdo_ext_t           *p_ext;\r
1476 \r
1477         BUS_ENTER( BUS_DBG_POWER );\r
1478 \r
1479         p_ext = p_dev_obj->DeviceExtension;\r
1480         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
1481 \r
1482         BUS_TRACE( BUS_DBG_POWER, \r
1483                 ("SET_POWER for FDO %p (ext %p): type %s, state %d, action %d, IRQL %d  \n",\r
1484                 p_dev_obj, p_ext,\r
1485                 (p_io_stack->Parameters.Power.Type)\r
1486                         ? "DevicePowerState" : "SystemPowerState",\r
1487                 p_io_stack->Parameters.Power.State.DeviceState, \r
1488                 p_io_stack->Parameters.Power.ShutdownType, KeGetCurrentIrql() ));\r
1489 \r
1490         switch( p_io_stack->Parameters.Power.Type )\r
1491         {\r
1492         case SystemPowerState:\r
1493                 /* Pass down and let the PDO driver handle it. */\r
1494                 p_ext->system_power_state = p_io_stack->Parameters.Power.State.SystemState;\r
1495                 *p_action = IrpIgnore;\r
1496                 status = STATUS_SUCCESS;\r
1497                 break;\r
1498 \r
1499         case DevicePowerState:\r
1500                 IoMarkIrpPending( p_irp );\r
1501                 if( p_io_stack->Parameters.Power.State.DeviceState == PowerDeviceD0 && \r
1502                         p_ext->system_power_state == PowerSystemWorking)\r
1503                 { /* power up */\r
1504                         /* If we're already powered up, just pass down. */\r
1505                         if( p_ext->device_power_state == PowerDeviceD0 )\r
1506                         {\r
1507                                 status = STATUS_SUCCESS;\r
1508                                 *p_action = IrpIgnore;\r
1509                                 break;\r
1510                         }\r
1511 \r
1512                         /* Process in I/O completion callback. */\r
1513                         IoCopyCurrentIrpStackLocationToNext( p_irp );\r
1514 #pragma warning( push, 3 )\r
1515                         IoSetCompletionRoutine( p_irp, __device_power_up_completion, NULL, \r
1516                                 TRUE, TRUE, TRUE );\r
1517 #pragma warning( pop )\r
1518                         PoCallDriver( p_ext->cl_ext.p_next_do, p_irp );\r
1519                 }\r
1520                 else\r
1521                 { /* power down */\r
1522 \r
1523                         /* Process in a work item - deregister_ca and HcaDeinit block. */\r
1524                         ASSERT( !p_ext->p_po_work_item );\r
1525                         p_ext->p_po_work_item = IoAllocateWorkItem( p_dev_obj );\r
1526                         if( !p_ext->p_po_work_item )\r
1527                         {\r
1528                                 status = STATUS_INSUFFICIENT_RESOURCES;\r
1529                                 break;\r
1530                         }\r
1531 \r
1532                         /* Process in work item callback. */\r
1533                         IoQueueWorkItem(\r
1534                                 p_ext->p_po_work_item, __device_power_down_workItem, DelayedWorkQueue, p_irp );\r
1535                 }\r
1536                 *p_action = IrpDoNothing;\r
1537                 status = STATUS_PENDING;\r
1538                 break;\r
1539 \r
1540         default:\r
1541                 /* Pass down and let the PDO driver handle it. */\r
1542                 *p_action = IrpIgnore;\r
1543                 status = STATUS_SUCCESS;\r
1544                 break;\r
1545         }\r
1546 \r
1547         if( !NT_SUCCESS( status ) )\r
1548                 *p_action = IrpComplete;\r
1549 \r
1550         BUS_EXIT( BUS_DBG_POWER );\r
1551         return status;\r
1552 }\r
1553 \r
1554 \r
1555 /*\r
1556  * A CA GUID of zero means that all devices should be reported.\r
1557  */\r
1558 NTSTATUS\r
1559 bus_get_relations(\r
1560         IN                              cl_qlist_t*     const                   p_pdo_list,\r
1561         IN              const   net64_t                                         ca_guid,\r
1562         IN                              IRP* const                                      p_irp )\r
1563 {\r
1564         NTSTATUS                        status;\r
1565         DEVICE_RELATIONS        *p_rel;\r
1566         cl_list_item_t          *p_list_item;\r
1567         bus_pdo_ext_t           *p_pdo_ext;\r
1568         size_t                          n_devs = 0;\r
1569 \r
1570         BUS_ENTER( BUS_DBG_PNP );\r
1571 \r
1572         /* Count the number of child devices. */\r
1573         for( p_list_item = cl_qlist_head( p_pdo_list );\r
1574                 p_list_item != cl_qlist_end( p_pdo_list );\r
1575                 p_list_item = cl_qlist_next( p_list_item ) )\r
1576         {\r
1577                 p_pdo_ext = PARENT_STRUCT( p_list_item, bus_pdo_ext_t, list_item );\r
1578 \r
1579                 if( !p_pdo_ext->b_present )\r
1580                 {\r
1581                         // mark it missing to be removed in port_remove\r
1582                         p_pdo_ext->b_reported_missing = TRUE;\r
1583                         /*\r
1584                          * We don't report a PDO that is no longer present.  This is how\r
1585                          * the PDO will get cleaned up.\r
1586                          */\r
1587                         BUS_TRACE( BUS_DBG_PNP, ("Don't report PDO! %s: PDO %p, ext %p, "\r
1588                                 "present %d, missing %d .\n",\r
1589                                 p_pdo_ext->cl_ext.vfptr_pnp_po->identity,\r
1590                                 p_pdo_ext->cl_ext.p_self_do, p_pdo_ext, p_pdo_ext->b_present,\r
1591                                 p_pdo_ext->b_reported_missing ) );\r
1592                         continue;\r
1593                 }\r
1594                 \r
1595                 if( ca_guid && p_pdo_ext->ca_guid != ca_guid )\r
1596                         continue;\r
1597 \r
1598                 n_devs++;\r
1599         }\r
1600 \r
1601         if( !n_devs )\r
1602         {\r
1603                 BUS_TRACE_EXIT( BUS_DBG_PNP, ("Found 0 PDOs ca_guid %I64x\n", ca_guid));\r
1604                 return STATUS_NO_SUCH_DEVICE;\r
1605         }\r
1606 \r
1607         BUS_TRACE( BUS_DBG_PNP, ("Found %d PDOs ca_guid %I64x\n", n_devs, ca_guid));\r
1608 \r
1609         /* Add space for our child IOUs. */\r
1610         status = cl_alloc_relations( p_irp, n_devs );\r
1611         if( !NT_SUCCESS( status ) )\r
1612         {\r
1613                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1614                         ("cl_alloc_relations returned %08x.\n", status) );\r
1615                 return status;\r
1616         }\r
1617 \r
1618         p_rel = (DEVICE_RELATIONS*)p_irp->IoStatus.Information;\r
1619 \r
1620         for( p_list_item = cl_qlist_head( p_pdo_list );\r
1621                 p_list_item != cl_qlist_end( p_pdo_list );\r
1622                 p_list_item = cl_qlist_next( p_list_item ) )\r
1623         {\r
1624                 p_pdo_ext = PARENT_STRUCT( p_list_item, bus_pdo_ext_t, list_item );\r
1625 \r
1626                 if( !p_pdo_ext->b_present )\r
1627                         continue;\r
1628 \r
1629                 if( ca_guid && p_pdo_ext->ca_guid != ca_guid )\r
1630                         continue;\r
1631 \r
1632                 BUS_TRACE( BUS_DBG_PNP, ("Reported PDO %p(=%p), ext %p\n", \r
1633                         p_pdo_ext->cl_ext.p_self_do, p_pdo_ext->cl_ext.p_pdo, p_pdo_ext ));\r
1634                 \r
1635                 p_rel->Objects[p_rel->Count] = p_pdo_ext->cl_ext.p_pdo;\r
1636                 ObReferenceObject( p_rel->Objects[p_rel->Count++] );\r
1637         }\r
1638 \r
1639         BUS_EXIT( BUS_DBG_PNP );\r
1640         return STATUS_SUCCESS;\r
1641 }\r
1642 \r
1643 \r
1644 /*\r
1645  * find a bus filter instance (p_bfi) given an *cl_obj: port_mgr or iou_mgr. \r
1646  */\r
1647 \r
1648 bus_filter_t *\r
1649 get_bfi_by_obj(IN int obj_type, IN cl_obj_t *p_obj )\r
1650 {\r
1651         bus_filter_t    *p_bfi;\r
1652         bus_filter_t    *matched=NULL;\r
1653 \r
1654         CL_ASSERT((obj_type == BFI_PORT_MGR_OBJ) || (obj_type == BFI_IOU_MGR_OBJ));\r
1655 \r
1656         lock_control_event();\r
1657 \r
1658         for(p_bfi=g_bus_filters; p_bfi < &g_bus_filters[MAX_BUS_FILTERS]; p_bfi++) {\r
1659 \r
1660                 if ( !p_bfi->p_bus_ext )\r
1661                         continue;\r
1662 \r
1663                 if ( obj_type == BFI_PORT_MGR_OBJ ) {\r
1664                         if ( p_obj == p_bfi->p_port_mgr_obj ) {\r
1665                                 matched = p_bfi;\r
1666                                 break;\r
1667                         }\r
1668                 }\r
1669                 else {\r
1670                         if ( p_obj == p_bfi->p_iou_mgr_obj ) {\r
1671                                 matched = p_bfi;\r
1672                                 break;\r
1673                         }\r
1674                 }\r
1675         }\r
1676         unlock_control_event();\r
1677 \r
1678         BUS_TRACE( BUS_DBG_PNP,\r
1679                                 ("cl_obj %p type %s_MGR_OBJ --> bfi[%d] %p\n", p_obj,\r
1680                                 (obj_type == BFI_PORT_MGR_OBJ ? "PORT": "IOU"),\r
1681                                 (matched ? (matched - g_bus_filters) : (-1)), matched ) );\r
1682 \r
1683         return matched;\r
1684 }\r
1685 \r
1686 /*\r
1687  * find a bus filter instance given an HCA guid.\r
1688  * BFIs are bound to GUIDs in fdo_start().\r
1689  */\r
1690 \r
1691 bus_filter_t *\r
1692 get_bfi_by_ca_guid( IN net64_t ca_guid )\r
1693 {\r
1694         bus_filter_t    *p_bfi;\r
1695         bus_filter_t    *matched=NULL;\r
1696 \r
1697         if ( ca_guid == 0ULL )\r
1698         {\r
1699                 matched = g_bus_filters;\r
1700                 BUS_TRACE( BUS_DBG_PNP, ("ERR guid %I64x -> bfi[0] %p\n",\r
1701                                                                 ca_guid, matched) );\r
1702                 CL_ASSERT( ca_guid );\r
1703                 return matched;\r
1704         }\r
1705 \r
1706         lock_control_event();\r
1707 \r
1708         for(p_bfi=g_bus_filters; p_bfi < &g_bus_filters[MAX_BUS_FILTERS]; p_bfi++)\r
1709         {\r
1710                 if ( !p_bfi->p_bus_ext )\r
1711                         continue;\r
1712 \r
1713                 if ( ca_guid == p_bfi->ca_guid )\r
1714                 {\r
1715                         matched = p_bfi;\r
1716                         break;\r
1717                 }\r
1718         }\r
1719         unlock_control_event();\r
1720 \r
1721 #if DBG\r
1722         if ( !matched )\r
1723         {\r
1724                 BUS_PRINT( BUS_DBG_PNP, ("No Match ca_guid 0x%I64x -> bfi[%d] %p\n",\r
1725                                                                         ca_guid, -1, matched ) );\r
1726         }\r
1727 #endif\r
1728         return matched;\r
1729 }\r
1730 \r
1731 \r
1732 bus_filter_t *\r
1733 alloc_bfi( IN DRIVER_OBJECT  *p_driver_obj, OUT int *p_instance_count )\r
1734 {\r
1735         bus_filter_t    *p_bfi;\r
1736         bus_filter_t    *matched=NULL;\r
1737 \r
1738     /* Using unsafe function so that the IRQL remains at PASSIVE_LEVEL.\r
1739      * IoCreateDeviceSecure & IoCreateSymbolicLink must be called at\r
1740      * PASSIVE_LEVEL.\r
1741          */\r
1742         lock_control_event();\r
1743 \r
1744         // find 1st unused bfi slot.\r
1745         for(p_bfi=g_bus_filters; p_bfi < &g_bus_filters[MAX_BUS_FILTERS]; p_bfi++)\r
1746         {\r
1747                 if ( !p_bfi->p_bus_ext )\r
1748                 {\r
1749                         /* temp setting until 'real' p_bus_ext is alloc; see bus_add_device.\r
1750                          * If p_bus_ext is ! 0, then bfi slot is allocated, although it\r
1751                          * may not yet have a bound CA guid; set set_get_\r
1752                          */\r
1753                         p_bfi->p_bus_ext = (bus_fdo_ext_t*)p_driver_obj;\r
1754                         matched = p_bfi;\r
1755                         *p_instance_count = ++g_bfi_InstanceCount; // record in-use\r
1756                         break;\r
1757                 }\r
1758         }\r
1759         unlock_control_event();\r
1760 \r
1761 #if DBG\r
1762         RtlStringCbPrintfA ( p_bfi->whoami,\r
1763                                                  sizeof(p_bfi->whoami),\r
1764                                                  "bfi-%d",\r
1765                                                  (g_bfi_InstanceCount - 1) );\r
1766 \r
1767         p_bfi->magic = BFI_MAGIC;\r
1768 #endif\r
1769 \r
1770         BUS_TRACE( BUS_DBG_PNP, ("%s %p\n",\r
1771                                 (matched ? matched->whoami:"Nobody"), matched) );\r
1772 \r
1773         return matched;\r
1774 }\r
1775 \r
1776 \r
1777 int\r
1778 free_bfi( IN  bus_filter_t  *p_bfi )\r
1779 {\r
1780         int     remaining;\r
1781 \r
1782         lock_control_event();\r
1783         p_bfi->p_bus_ext = NULL;\r
1784         p_bfi->ca_guid = 0ULL;\r
1785         remaining = --g_bfi_InstanceCount; // one less bfi in-use\r
1786         unlock_control_event();\r
1787         \r
1788         return remaining;\r
1789 }\r
1790 \r
1791 int\r
1792 get_bfi_count( void )\r
1793 {\r
1794         int     ic;\r
1795 \r
1796         lock_control_event();\r
1797         ic = g_bfi_InstanceCount;\r
1798         unlock_control_event();\r
1799         \r
1800         return ic;\r
1801 }\r
1802 \r
1803 #if DBG\r
1804 char *get_obj_state_str(cl_state_t state)\r
1805 {\r
1806         switch( state ) {\r
1807           case CL_UNINITIALIZED:\r
1808                 return "UNINITIALIZED";\r
1809           case CL_INITIALIZED:\r
1810                 return "INITIALIZED";\r
1811           case CL_DESTROYING:\r
1812                 return "DESTROYING";\r
1813           case CL_DESTROYED:\r
1814                 return "DESTROYED";\r
1815           default:\r
1816                 break;\r
1817         }\r
1818         return "Err - Bad obj state";\r
1819 }\r
1820 #endif\r
1821 \r