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