[IBBUS] boot in SAN environment.
[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 = STATUS_SUCCESS; /*default to success*/\r
657         bus_fdo_ext_t           *p_ext;\r
658         bus_filter_t            *p_bfi;\r
659         int                                     waitLoop = 0;\r
660 \r
661         BUS_ENTER( BUS_DBG_PNP );\r
662 \r
663         p_ext = p_dev_obj->DeviceExtension;\r
664 \r
665         if ( !p_ext->bus_filter )\r
666         {\r
667                 /* BFI has already been released */\r
668                 *p_action = IrpComplete;\r
669                 BUS_TRACE_EXIT( BUS_DBG_PNP, ("NULL BFI\n") );\r
670                 return STATUS_SUCCESS;\r
671         }\r
672 \r
673         p_bfi = p_ext->bus_filter;\r
674         CL_ASSERT( p_bfi->magic == BFI_MAGIC );\r
675 \r
676         while ( p_bfi->ca_guid == 0ULL )\r
677         {\r
678                 /* HCA not yet bound to a BFI slot (no PNP ADD event seen), no bus\r
679                  * relations yet.\r
680                  */\r
681                 BUS_PRINT(BUS_DBG_ERROR, ("%s ca_guid %I64x\n",p_bfi->whoami,\r
682                                                                 p_bfi->ca_guid));\r
683                 cl_thread_suspend( 100 );       /* suspend for 100 ms */\r
684                 waitLoop++;\r
685                 if(waitLoop>50) break;\r
686         }\r
687         if ( p_bfi->ca_guid != 0ULL )\r
688         {\r
689                 status = port_mgr_get_bus_relations( p_bfi->ca_guid, p_irp );\r
690                 if( status == STATUS_SUCCESS || \r
691                         status == STATUS_NO_SUCH_DEVICE )\r
692                 {\r
693                         status = iou_mgr_get_bus_relations( p_bfi->ca_guid, p_irp );\r
694                 }\r
695                 if( status == STATUS_NO_SUCH_DEVICE )\r
696                         status = STATUS_SUCCESS;\r
697         }\r
698 \r
699         switch( status )\r
700         {\r
701         case STATUS_NO_SUCH_DEVICE:\r
702                 *p_action = IrpSkip;\r
703                 status = STATUS_SUCCESS;\r
704                 break;\r
705 \r
706         case STATUS_SUCCESS:\r
707                 *p_action = IrpPassDown;\r
708                 break;\r
709 \r
710         default:\r
711                 *p_action = IrpComplete;\r
712                 break;\r
713         }\r
714 \r
715         BUS_EXIT( BUS_DBG_PNP );\r
716         return status;\r
717 }\r
718 \r
719 \r
720 void\r
721 al_ref_ifc(\r
722         IN                              DEVICE_OBJECT*                          p_dev_obj )\r
723 {\r
724         bus_fdo_ext_t   *p_ext;\r
725 \r
726         BUS_ENTER( BUS_DBG_PNP );\r
727 \r
728         p_ext = p_dev_obj->DeviceExtension;\r
729 \r
730         cl_atomic_inc( &p_ext->n_al_ifc_ref );\r
731         ObReferenceObject( p_dev_obj );\r
732 \r
733         BUS_EXIT( BUS_DBG_PNP );\r
734 }\r
735 \r
736 \r
737 void\r
738 al_deref_ifc(\r
739         IN                              DEVICE_OBJECT*                          p_dev_obj )\r
740 {\r
741         bus_fdo_ext_t   *p_ext;\r
742 \r
743         BUS_ENTER( BUS_DBG_PNP );\r
744 \r
745         p_ext = p_dev_obj->DeviceExtension;\r
746 \r
747         cl_atomic_dec( &p_ext->n_al_ifc_ref );\r
748         ObDereferenceObject( p_dev_obj );\r
749 \r
750         CL_ASSERT(p_ext->bus_filter);\r
751         BUS_PRINT( BUS_DBG_PNP, ("%s CA_guid %I64x al_ifc_ref %d\n",\r
752                                         p_ext->bus_filter->whoami, p_ext->bus_filter->ca_guid,\r
753                                         p_ext->n_al_ifc_ref) );\r
754 \r
755         BUS_EXIT( BUS_DBG_PNP );\r
756 }\r
757 \r
758 \r
759 void\r
760 al_ref_ci_ifc(\r
761         IN                              DEVICE_OBJECT*                          p_dev_obj )\r
762 {\r
763         bus_fdo_ext_t   *p_ext;\r
764 \r
765         BUS_ENTER( BUS_DBG_PNP );\r
766 \r
767         p_ext = p_dev_obj->DeviceExtension;\r
768 \r
769         cl_atomic_inc( &p_ext->n_ci_ifc_ref );\r
770         ObReferenceObject( p_dev_obj );\r
771 \r
772         BUS_EXIT( BUS_DBG_PNP );\r
773 }\r
774 \r
775 \r
776 void\r
777 al_deref_ci_ifc(\r
778         IN                              DEVICE_OBJECT*                          p_dev_obj )\r
779 {\r
780         bus_fdo_ext_t   *p_ext;\r
781 \r
782         BUS_ENTER( BUS_DBG_PNP );\r
783 \r
784         p_ext = p_dev_obj->DeviceExtension;\r
785 \r
786         cl_atomic_dec( &p_ext->n_ci_ifc_ref );\r
787         ObDereferenceObject( p_dev_obj );\r
788 \r
789         CL_ASSERT(p_ext->bus_filter);\r
790         BUS_PRINT( BUS_DBG_PNP, ("%s CA_guid %I64x ci_ifc_ref %d\n",\r
791                                                 p_ext->bus_filter->whoami, p_ext->bus_filter->ca_guid,\r
792                                                 p_ext->n_ci_ifc_ref) );\r
793 \r
794         BUS_EXIT( BUS_DBG_PNP );\r
795 }\r
796 \r
797 \r
798 static NTSTATUS\r
799 __query_al_ifc(\r
800         IN                                      DEVICE_OBJECT* const            p_dev_obj,\r
801         IN                                      IO_STACK_LOCATION* const        p_io_stack )\r
802 {\r
803         ib_al_ifc_t             *p_ifc;\r
804 \r
805         BUS_ENTER( BUS_DBG_PNP );\r
806 \r
807         if( p_io_stack->Parameters.QueryInterface.Version != \r
808                 AL_INTERFACE_VERSION )\r
809         {\r
810                 BUS_TRACE_EXIT( BUS_DBG_PNP, ("Incorrect interface version (%d)\n",\r
811                         p_io_stack->Parameters.QueryInterface.Version ) );\r
812                 return STATUS_NOT_SUPPORTED;\r
813         }\r
814 \r
815         if( p_io_stack->Parameters.QueryInterface.Size < sizeof(ib_al_ifc_t) )\r
816         {\r
817                 BUS_TRACE_EXIT( BUS_DBG_PNP, \r
818                         ("Buffer too small (%d given, %d required).\n",\r
819                         p_io_stack->Parameters.QueryInterface.Size, sizeof(ib_al_ifc_t)) );\r
820                 return STATUS_BUFFER_TOO_SMALL;\r
821         }\r
822 \r
823         // Copy the interface.\r
824         p_ifc = (ib_al_ifc_t*)p_io_stack->Parameters.QueryInterface.Interface;\r
825 \r
826         p_ifc->wdm.Size = sizeof(ib_al_ifc_t);\r
827         p_ifc->wdm.Version = AL_INTERFACE_VERSION;\r
828         p_ifc->wdm.Context = p_dev_obj;\r
829         p_ifc->wdm.InterfaceReference = al_ref_ifc;\r
830         p_ifc->wdm.InterfaceDereference = al_deref_ifc;\r
831 \r
832         __set_ifc( p_ifc );\r
833 \r
834         // take the reference before returning.\r
835         al_ref_ifc( p_dev_obj );\r
836         BUS_EXIT( BUS_DBG_PNP );\r
837         return STATUS_SUCCESS;\r
838 }\r
839 \r
840 static void\r
841 __set_ifc(\r
842                 OUT                     ib_al_ifc_t* const                      p_ifc )\r
843 {\r
844         BUS_ENTER( BUS_DBG_PNP );\r
845 \r
846         p_ifc->wdm.Size = sizeof(ib_al_ifc_t);\r
847         p_ifc->wdm.InterfaceReference = al_ref_ifc;\r
848         p_ifc->wdm.InterfaceDereference = al_deref_ifc;\r
849 \r
850         p_ifc->sync_destroy = ib_sync_destroy;\r
851         p_ifc->open_ca = ib_open_ca;\r
852         p_ifc->query_ca = ib_query_ca;\r
853         p_ifc->get_dev = get_ca_dev;\r
854         p_ifc->close_ca = ib_close_ca;\r
855         p_ifc->alloc_pd = ib_alloc_pd;\r
856         p_ifc->dealloc_pd = ib_dealloc_pd;\r
857         p_ifc->create_av = ib_create_av;\r
858         p_ifc->query_av = ib_query_av;\r
859         p_ifc->modify_av = ib_modify_av;\r
860         p_ifc->destroy_av = ib_destroy_av;\r
861         p_ifc->create_qp = ib_create_qp;\r
862         p_ifc->get_spl_qp = ib_get_spl_qp;\r
863         p_ifc->query_qp = ib_query_qp;\r
864         p_ifc->modify_qp = ib_modify_qp;\r
865         p_ifc->destroy_qp = ib_destroy_qp;\r
866         p_ifc->create_cq = ib_create_cq;\r
867         p_ifc->modify_cq = ib_modify_cq;\r
868         p_ifc->query_cq = ib_query_cq;\r
869         p_ifc->destroy_cq = ib_destroy_cq;\r
870         p_ifc->reg_mem = ib_reg_mem;\r
871         p_ifc->reg_phys = ib_reg_phys;\r
872         p_ifc->query_mr = ib_query_mr;\r
873         p_ifc->rereg_mem = ib_rereg_mem;\r
874         p_ifc->reg_shmid = ib_reg_shmid;\r
875         p_ifc->dereg_mr = ib_dereg_mr;\r
876         p_ifc->create_mw = ib_create_mw;\r
877         p_ifc->query_mw = ib_query_mw;\r
878         p_ifc->bind_mw = ib_bind_mw;\r
879         p_ifc->destroy_mw = ib_destroy_mw;\r
880         p_ifc->post_send = ib_post_send;\r
881         p_ifc->post_recv = ib_post_recv;\r
882         p_ifc->send_mad = ib_send_mad;\r
883         p_ifc->cancel_mad = ib_cancel_mad;\r
884         p_ifc->poll_cq = ib_poll_cq;\r
885         p_ifc->rearm_cq = ib_rearm_cq;\r
886         p_ifc->join_mcast = ib_join_mcast;\r
887         p_ifc->leave_mcast = ib_leave_mcast;\r
888         p_ifc->local_mad = ib_local_mad;\r
889         p_ifc->cm_listen = ib_cm_listen;\r
890         p_ifc->cm_cancel = ib_cm_cancel;\r
891         p_ifc->cm_req = ib_cm_req;\r
892         p_ifc->cm_rep = ib_cm_rep;\r
893         p_ifc->cm_rtu = ib_cm_rtu;\r
894         p_ifc->cm_rej = ib_cm_rej;\r
895         p_ifc->cm_mra = ib_cm_mra;\r
896         p_ifc->cm_lap = ib_cm_lap;\r
897         p_ifc->cm_apr = ib_cm_apr;\r
898         p_ifc->force_apm = ib_force_apm;\r
899         p_ifc->cm_dreq = ib_cm_dreq;\r
900         p_ifc->cm_drep = ib_cm_drep;\r
901         p_ifc->cm_handoff = ib_cm_handoff;\r
902         p_ifc->create_ioc = ib_create_ioc;\r
903         p_ifc->destroy_ioc = ib_destroy_ioc;\r
904         p_ifc->reg_ioc = ib_reg_ioc;\r
905         p_ifc->add_svc_entry = ib_add_svc_entry;\r
906         p_ifc->remove_svc_entry = ib_remove_svc_entry;\r
907         p_ifc->get_ca_guids = ib_get_ca_guids;\r
908         p_ifc->get_ca_by_gid = ib_get_ca_by_gid;\r
909         p_ifc->get_port_by_gid = ib_get_port_by_gid;\r
910         p_ifc->create_mad_pool = ib_create_mad_pool;\r
911         p_ifc->destroy_mad_pool = ib_destroy_mad_pool;\r
912         p_ifc->reg_mad_pool = ib_reg_mad_pool;\r
913         p_ifc->dereg_mad_pool = ib_dereg_mad_pool;\r
914         p_ifc->get_mad = ib_get_mad;\r
915         p_ifc->put_mad = ib_put_mad;\r
916         p_ifc->init_dgrm_svc = ib_init_dgrm_svc;\r
917         p_ifc->reg_mad_svc = ib_reg_mad_svc;\r
918         p_ifc->reg_svc = ib_reg_svc;\r
919         p_ifc->dereg_svc = ib_dereg_svc;\r
920         p_ifc->query = ib_query;\r
921         p_ifc->cancel_query = ib_cancel_query;\r
922         p_ifc->reg_pnp = ib_reg_pnp;\r
923         p_ifc->dereg_pnp = ib_dereg_pnp;\r
924         p_ifc->subscribe = ib_subscribe;\r
925         p_ifc->unsubscribe = ib_unsubscribe;\r
926         p_ifc->reject_ioc = ib_reject_ioc;\r
927         p_ifc->ci_call = ib_ci_call;\r
928         p_ifc->open_al = ib_open_al;\r
929         p_ifc->close_al = ib_close_al;\r
930         p_ifc->get_err_str = ib_get_err_str;\r
931         p_ifc->get_wc_status_str = ib_get_wc_status_str;\r
932         p_ifc->create_mlnx_fmr = mlnx_create_fmr;\r
933         p_ifc->map_phys_mlnx_fmr = mlnx_map_phys_fmr;\r
934         p_ifc->unmap_mlnx_fmr = mlnx_unmap_fmr;\r
935         p_ifc->destroy_mlnx_fmr = mlnx_destroy_fmr;\r
936         p_ifc->create_mlnx_fmr_pool = mlnx_create_fmr_pool;\r
937         p_ifc->destroy_mlnx_fmr_pool = mlnx_destroy_fmr_pool;\r
938         p_ifc->map_phys_mlnx_fmr_pool = mlnx_map_phys_fmr_pool;\r
939         p_ifc->unmap_mlnx_fmr_pool = mlnx_unmap_fmr_pool;\r
940         p_ifc->flush_mlnx_fmr_pool = mlnx_flush_fmr_pool;\r
941         p_ifc->create_srq = ib_create_srq;\r
942         p_ifc->modify_srq = ib_modify_srq;\r
943         p_ifc->query_srq = ib_query_srq;\r
944         p_ifc->destroy_srq = ib_destroy_srq;\r
945         p_ifc->post_srq_recv = ib_post_srq_recv;\r
946 \r
947         BUS_EXIT( BUS_DBG_PNP );\r
948 }\r
949 \r
950 \r
951 static NTSTATUS\r
952 __get_relations(\r
953         IN              const   net64_t                                         ca_guid,\r
954         IN                              IRP* const                                      p_irp )\r
955 {\r
956         UNUSED_PARAM( ca_guid );\r
957         UNUSED_PARAM( p_irp );\r
958 \r
959         BUS_ENTER( BUS_DBG_PNP );\r
960 \r
961         /*\r
962          * Now that ibbus is in the same device stack as the HCA driver, skip\r
963          * returning relations here as ibbus has already done the deed.\r
964          * This interface remains to minimize changes to HCA drivers for now.\r
965          */\r
966 \r
967         BUS_EXIT( BUS_DBG_PNP );\r
968         return STATUS_SUCCESS;\r
969 }\r
970 \r
971 \r
972 static NTSTATUS\r
973 __query_ci_ifc(\r
974         IN                                      DEVICE_OBJECT* const            p_dev_obj,\r
975         IN                                      IO_STACK_LOCATION* const        p_io_stack )\r
976 {\r
977         ib_ci_ifc_t             *p_ifc;\r
978 \r
979         BUS_ENTER( BUS_DBG_PNP );\r
980 \r
981         if( p_io_stack->Parameters.QueryInterface.Version != \r
982                 IB_CI_INTERFACE_VERSION )\r
983         {\r
984                 BUS_TRACE_EXIT( BUS_DBG_PNP, ("Incorrect interface version (%d)\n",\r
985                         p_io_stack->Parameters.QueryInterface.Version ) );\r
986                 return STATUS_NOT_SUPPORTED;\r
987         }\r
988 \r
989         if( p_io_stack->Parameters.QueryInterface.Size < sizeof(ib_ci_ifc_t) )\r
990         {\r
991                 BUS_TRACE_EXIT( BUS_DBG_PNP, \r
992                         ("Buffer too small (%d given, %d required).\n",\r
993                         p_io_stack->Parameters.QueryInterface.Size, sizeof(ib_ci_ifc_t)) );\r
994                 return STATUS_BUFFER_TOO_SMALL;\r
995         }\r
996 \r
997         /* Copy the interface. */\r
998         p_ifc = (ib_ci_ifc_t*)p_io_stack->Parameters.QueryInterface.Interface;\r
999 \r
1000         p_ifc->wdm.Size = sizeof(ib_ci_ifc_t);\r
1001         p_ifc->wdm.Version = IB_CI_INTERFACE_VERSION;\r
1002         p_ifc->wdm.Context = p_dev_obj;\r
1003         p_ifc->wdm.InterfaceReference = al_ref_ci_ifc;\r
1004         p_ifc->wdm.InterfaceDereference = al_deref_ci_ifc;\r
1005 \r
1006         /* Set the entry points. */\r
1007         p_ifc->register_ca = ib_register_ca;\r
1008         p_ifc->deregister_ca = ib_deregister_ca;\r
1009         p_ifc->get_relations = __get_relations;\r
1010         p_ifc->get_err_str = ib_get_err_str;\r
1011 \r
1012         /* take the reference before returning. */\r
1013         al_ref_ci_ifc( p_dev_obj );\r
1014         BUS_EXIT( BUS_DBG_PNP );\r
1015         return STATUS_SUCCESS;\r
1016 }\r
1017 \r
1018 \r
1019 static NTSTATUS\r
1020 __query_cm_ifc(\r
1021         IN                                      DEVICE_OBJECT* const            p_dev_obj,\r
1022         IN                                      IO_STACK_LOCATION* const        p_io_stack )\r
1023 {\r
1024         INFINIBAND_INTERFACE_CM *p_ifc;\r
1025 \r
1026         BUS_ENTER( BUS_DBG_PNP );\r
1027 \r
1028         if( p_io_stack->Parameters.QueryInterface.Version != IbaCmVersion(1, 0) )\r
1029         {\r
1030                 BUS_TRACE_EXIT( BUS_DBG_PNP, ("Incorrect interface version (%d)\n",\r
1031                         p_io_stack->Parameters.QueryInterface.Version ) );\r
1032                 return STATUS_NOT_SUPPORTED;\r
1033         }\r
1034 \r
1035         if( p_io_stack->Parameters.QueryInterface.Size < sizeof(INFINIBAND_INTERFACE_CM) )\r
1036         {\r
1037                 BUS_TRACE_EXIT( BUS_DBG_PNP, \r
1038                         ("Buffer too small (%d given, %d required).\n",\r
1039                         p_io_stack->Parameters.QueryInterface.Size, sizeof(INFINIBAND_INTERFACE_CM)) );\r
1040                 return STATUS_BUFFER_TOO_SMALL;\r
1041         }\r
1042 \r
1043         /* Copy the interface. */\r
1044         p_ifc = (INFINIBAND_INTERFACE_CM*)p_io_stack->Parameters.QueryInterface.Interface;\r
1045 \r
1046         p_ifc->InterfaceHeader.Size = sizeof(INFINIBAND_INTERFACE_CM);\r
1047         p_ifc->InterfaceHeader.Version = IbaCmVersion(1, 0);\r
1048         p_ifc->InterfaceHeader.Context = p_dev_obj;\r
1049         p_ifc->InterfaceHeader.InterfaceReference = al_ref_ifc;\r
1050         p_ifc->InterfaceHeader.InterfaceDereference = al_deref_ifc;\r
1051         cm_get_interface(&p_ifc->CM);\r
1052 \r
1053         /* take the reference before returning. */\r
1054         al_ref_ifc( p_dev_obj );\r
1055         BUS_EXIT( BUS_DBG_PNP );\r
1056         return STATUS_SUCCESS;\r
1057 }\r
1058 \r
1059 \r
1060 static NTSTATUS\r
1061 fdo_query_interface(\r
1062         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
1063         IN                                      IRP* const                              p_irp, \r
1064                 OUT                             cl_irp_action_t* const  p_action )\r
1065 {\r
1066         NTSTATUS                        status;\r
1067         IO_STACK_LOCATION       *p_io_stack;\r
1068 \r
1069         BUS_ENTER( BUS_DBG_PNP );\r
1070 \r
1071         PAGED_CODE();\r
1072 \r
1073         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
1074         \r
1075         /* Compare requested GUID with our supported interface GUIDs. */\r
1076         if( IsEqualGUID( p_io_stack->Parameters.QueryInterface.InterfaceType,\r
1077                 &GUID_IB_AL_INTERFACE ) )\r
1078         {\r
1079                 status = __query_al_ifc( p_dev_obj, p_io_stack );\r
1080         }\r
1081         else if( IsEqualGUID( p_io_stack->Parameters.QueryInterface.InterfaceType,\r
1082                 &GUID_IB_CI_INTERFACE ) )\r
1083         {\r
1084                 status = __query_ci_ifc( p_dev_obj, p_io_stack );\r
1085         }\r
1086         else if( IsEqualGUID( p_io_stack->Parameters.QueryInterface.InterfaceType,\r
1087                 &GUID_INFINIBAND_INTERFACE_CM ) )\r
1088         {\r
1089                 status = __query_cm_ifc( p_dev_obj, p_io_stack );\r
1090         }\r
1091         else\r
1092         {\r
1093                 status = p_irp->IoStatus.Status;\r
1094         }\r
1095 \r
1096         if( NT_SUCCESS( status ) )\r
1097                 *p_action = IrpSkip;\r
1098         else if( status == STATUS_BUFFER_TOO_SMALL )\r
1099                 *p_action = IrpComplete;\r
1100         else\r
1101                 *p_action = IrpIgnore;\r
1102 \r
1103         BUS_EXIT( BUS_DBG_PNP );\r
1104         return status;\r
1105 }\r
1106 \r
1107 \r
1108 static NTSTATUS\r
1109 __fdo_query_power(\r
1110         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1111         IN                              IRP* const                                      p_irp,\r
1112                 OUT                     cl_irp_action_t* const          p_action )\r
1113 {\r
1114         NTSTATUS                        status = STATUS_SUCCESS;\r
1115         IO_STACK_LOCATION       *p_io_stack;\r
1116 \r
1117         BUS_ENTER( BUS_DBG_POWER );\r
1118 \r
1119         UNUSED_PARAM( p_dev_obj );\r
1120 \r
1121         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
1122 \r
1123         switch( p_io_stack->Parameters.Power.Type )\r
1124         {\r
1125         case SystemPowerState:\r
1126                 /* Fail any requests to hibernate or sleep the system. */\r
1127                 switch( p_io_stack->Parameters.Power.State.SystemState )\r
1128                 {\r
1129                         case PowerSystemHibernate:\r
1130                         case PowerSystemSleeping1:      // STANDBY support\r
1131                         case PowerSystemWorking:\r
1132                         case PowerSystemShutdown:\r
1133                                 break;\r
1134 \r
1135                         default:\r
1136                                 status = STATUS_NOT_SUPPORTED;\r
1137                 }\r
1138                 break;\r
1139 \r
1140         case DevicePowerState:\r
1141                 /* Fail any query for low power states. */\r
1142                 switch( p_io_stack->Parameters.Power.State.DeviceState )\r
1143                 {\r
1144                 case PowerDeviceD0:\r
1145                 case PowerDeviceD3:\r
1146                         /* We only support fully powered or off power states. */\r
1147                         break;\r
1148 \r
1149                 default:\r
1150                         status = STATUS_NOT_SUPPORTED;\r
1151                 }\r
1152                 break;\r
1153         }\r
1154 \r
1155         if( status == STATUS_NOT_SUPPORTED )\r
1156                 *p_action = IrpComplete;\r
1157         else\r
1158                 *p_action = IrpSkip;\r
1159 \r
1160         BUS_EXIT( BUS_DBG_POWER );\r
1161         return status;\r
1162 }\r
1163 \r
1164 \r
1165 static void\r
1166 __request_power_completion(\r
1167         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
1168         IN                              UCHAR                                           minor_function,\r
1169         IN                              POWER_STATE                                     power_state,\r
1170         IN                              void                                            *context,\r
1171         IN                              IO_STATUS_BLOCK                         *p_io_status )\r
1172 {\r
1173         IRP                                     *p_irp;\r
1174         cl_pnp_po_ext_t         *p_ext;\r
1175 \r
1176         BUS_ENTER( BUS_DBG_PNP );\r
1177 \r
1178         UNUSED_PARAM( minor_function );\r
1179         UNUSED_PARAM( power_state );\r
1180 \r
1181         p_irp = (IRP*)context;\r
1182         p_ext = p_dev_obj->DeviceExtension;\r
1183 \r
1184         /* Propagate the device IRP status to the system IRP status. */\r
1185         p_irp->IoStatus.Status = p_io_status->Status;\r
1186 \r
1187         /* Continue Power IRP processing. */\r
1188         PoStartNextPowerIrp( p_irp );\r
1189         IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
1190         IoReleaseRemoveLock( &p_ext->remove_lock, p_irp );\r
1191         BUS_EXIT( BUS_DBG_PNP );\r
1192 }\r
1193 \r
1194 \r
1195 /*NOTE: Completion routines must NEVER be pageable. */\r
1196 static NTSTATUS\r
1197 __set_power_completion(\r
1198         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
1199         IN                              IRP                                                     *p_irp,\r
1200         IN                              void                                            *context )\r
1201 {\r
1202         NTSTATUS                        status;\r
1203         POWER_STATE                     state;\r
1204         bus_fdo_ext_t           *p_ext;\r
1205         IO_STACK_LOCATION       *p_io_stack;\r
1206 \r
1207         BUS_ENTER( BUS_DBG_PNP );\r
1208 \r
1209         UNUSED_PARAM( context );\r
1210 \r
1211         p_ext = p_dev_obj->DeviceExtension;\r
1212         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
1213 \r
1214         if( !NT_SUCCESS( p_irp->IoStatus.Status ) )\r
1215         {\r
1216                 PoStartNextPowerIrp( p_irp );\r
1217                 IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
1218                 BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
1219                         ("IRP_MN_SET_POWER for system failed by lower driver with %08x.\n",\r
1220                         p_irp->IoStatus.Status) );\r
1221                 return STATUS_SUCCESS;\r
1222         }\r
1223 \r
1224         state.DeviceState = \r
1225                 p_ext->po_state[p_io_stack->Parameters.Power.State.SystemState];\r
1226 \r
1227         /*\r
1228          * Send a device power IRP to our devnode.  Using our device object will\r
1229          * only work on win2k and other NT based systems.\r
1230          */\r
1231         status = PoRequestPowerIrp( p_dev_obj, IRP_MN_SET_POWER, state,\r
1232                 __request_power_completion, p_irp, NULL );\r
1233 \r
1234         if( status != STATUS_PENDING )\r
1235         {\r
1236                 PoStartNextPowerIrp( p_irp );\r
1237                 /* Propagate the failure. */\r
1238                 p_irp->IoStatus.Status = status;\r
1239                 IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
1240                 IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
1241                 BUS_TRACE( BUS_DBG_ERROR,\r
1242                         ("PoRequestPowerIrp returned %08x.\n", status) );\r
1243         }\r
1244 \r
1245         BUS_EXIT( BUS_DBG_PNP );\r
1246         return STATUS_MORE_PROCESSING_REQUIRED;\r
1247 }\r
1248 \r
1249 \r
1250 static NTSTATUS\r
1251 __fdo_set_power(\r
1252         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1253         IN                              IRP* const                                      p_irp,\r
1254                 OUT                     cl_irp_action_t* const          p_action )\r
1255 {\r
1256         NTSTATUS                        status;\r
1257         IO_STACK_LOCATION       *p_io_stack;\r
1258         bus_fdo_ext_t           *p_ext;\r
1259 \r
1260         BUS_ENTER( BUS_DBG_POWER );\r
1261 \r
1262         p_ext = p_dev_obj->DeviceExtension;\r
1263         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
1264 \r
1265         BUS_TRACE( BUS_DBG_POWER, \r
1266                 ("SET_POWER for FDO %p (ext %p): type %s, state %d, action %d \n",\r
1267                 p_dev_obj, p_ext,\r
1268                 (p_io_stack->Parameters.Power.Type)\r
1269                         ? "DevicePowerState" : "SystemPowerState",\r
1270                 p_io_stack->Parameters.Power.State.DeviceState, \r
1271                 p_io_stack->Parameters.Power.ShutdownType ));\r
1272 \r
1273         switch( p_io_stack->Parameters.Power.Type )\r
1274         {\r
1275         case SystemPowerState:\r
1276 #if 0\r
1277                 /*\r
1278                  * Process on the way up the stack.  We cannot block since the \r
1279                  * power dispatch function can be called at elevated IRQL if the\r
1280                  * device is in a paging/hibernation/crash dump path.\r
1281                  */\r
1282                 IoMarkIrpPending( p_irp );\r
1283                 IoCopyCurrentIrpStackLocationToNext( p_irp );\r
1284 #pragma warning( push, 3 )\r
1285                 IoSetCompletionRoutine( p_irp, __set_power_completion, NULL, \r
1286                         TRUE, TRUE, TRUE );\r
1287 #pragma warning( pop )\r
1288                 PoCallDriver( p_ext->cl_ext.p_next_do, p_irp );\r
1289 \r
1290                 *p_action = IrpDoNothing;\r
1291                 status = STATUS_PENDING;\r
1292                 break;\r
1293 #endif\r
1294         case DevicePowerState:\r
1295         default:\r
1296                 /* Pass down and let the PDO driver handle it. */\r
1297                 *p_action = IrpIgnore;\r
1298                 status = STATUS_SUCCESS;\r
1299                 break;\r
1300         }\r
1301 \r
1302         BUS_EXIT( BUS_DBG_POWER );\r
1303         return status;\r
1304 }\r
1305 \r
1306 \r
1307 /*\r
1308  * A CA GUID of zero means that all devices should be reported.\r
1309  */\r
1310 NTSTATUS\r
1311 bus_get_relations(\r
1312         IN                              cl_qlist_t*     const                   p_pdo_list,\r
1313         IN              const   net64_t                                         ca_guid,\r
1314         IN                              IRP* const                                      p_irp )\r
1315 {\r
1316         NTSTATUS                        status;\r
1317         DEVICE_RELATIONS        *p_rel;\r
1318         cl_list_item_t          *p_list_item;\r
1319         bus_pdo_ext_t           *p_pdo_ext;\r
1320         size_t                          n_devs = 0;\r
1321 \r
1322         BUS_ENTER( BUS_DBG_PNP );\r
1323 \r
1324         /* Count the number of child devices. */\r
1325         for( p_list_item = cl_qlist_head( p_pdo_list );\r
1326                 p_list_item != cl_qlist_end( p_pdo_list );\r
1327                 p_list_item = cl_qlist_next( p_list_item ) )\r
1328         {\r
1329                 p_pdo_ext = PARENT_STRUCT( p_list_item, bus_pdo_ext_t, list_item );\r
1330 \r
1331                 if( !p_pdo_ext->b_present )\r
1332                 {\r
1333                         // mark it missing to be removed in port_remove\r
1334                         p_pdo_ext->b_reported_missing = TRUE;\r
1335                         /*\r
1336                          * We don't report a PDO that is no longer present.  This is how\r
1337                          * the PDO will get cleaned up.\r
1338                          */\r
1339                         BUS_TRACE( BUS_DBG_PNP, ("Don't report PDO! %s: PDO %p, ext %p, "\r
1340                                 "present %d, missing %d .\n",\r
1341                                 p_pdo_ext->cl_ext.vfptr_pnp_po->identity,\r
1342                                 p_pdo_ext->cl_ext.p_self_do, p_pdo_ext, p_pdo_ext->b_present,\r
1343                                 p_pdo_ext->b_reported_missing ) );\r
1344                         continue;\r
1345                 }\r
1346                 \r
1347                 if( ca_guid && p_pdo_ext->ca_guid != ca_guid )\r
1348                         continue;\r
1349 \r
1350                 n_devs++;\r
1351         }\r
1352 \r
1353         if( !n_devs )\r
1354         {\r
1355                 BUS_TRACE_EXIT( BUS_DBG_PNP, ("Found 0 PDOs ca_guid %I64x\n", ca_guid));\r
1356                 return STATUS_NO_SUCH_DEVICE;\r
1357         }\r
1358 \r
1359         BUS_TRACE( BUS_DBG_PNP, ("Found %d PDOs ca_guid %I64x\n", n_devs, ca_guid));\r
1360 \r
1361         /* Add space for our child IOUs. */\r
1362         status = cl_alloc_relations( p_irp, n_devs );\r
1363         if( !NT_SUCCESS( status ) )\r
1364         {\r
1365                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1366                         ("cl_alloc_relations returned %08x.\n", status) );\r
1367                 return status;\r
1368         }\r
1369 \r
1370         p_rel = (DEVICE_RELATIONS*)p_irp->IoStatus.Information;\r
1371 \r
1372         for( p_list_item = cl_qlist_head( p_pdo_list );\r
1373                 p_list_item != cl_qlist_end( p_pdo_list );\r
1374                 p_list_item = cl_qlist_next( p_list_item ) )\r
1375         {\r
1376                 p_pdo_ext = PARENT_STRUCT( p_list_item, bus_pdo_ext_t, list_item );\r
1377 \r
1378                 if( !p_pdo_ext->b_present )\r
1379                         continue;\r
1380 \r
1381                 if( ca_guid && p_pdo_ext->ca_guid != ca_guid )\r
1382                         continue;\r
1383 \r
1384                 BUS_TRACE( BUS_DBG_PNP, ("Reported PDO %p(=%p), ext %p\n", \r
1385                         p_pdo_ext->cl_ext.p_self_do, p_pdo_ext->cl_ext.p_pdo, p_pdo_ext ));\r
1386                 \r
1387                 p_rel->Objects[p_rel->Count] = p_pdo_ext->cl_ext.p_pdo;\r
1388                 ObReferenceObject( p_rel->Objects[p_rel->Count++] );\r
1389         }\r
1390 \r
1391         BUS_EXIT( BUS_DBG_PNP );\r
1392         return STATUS_SUCCESS;\r
1393 }\r
1394 \r
1395 \r
1396 /*\r
1397  * find a bus filter instance (p_bfi) given an *cl_obj: port_mgr or iou_mgr. \r
1398  */\r
1399 \r
1400 bus_filter_t *\r
1401 get_bfi_by_obj(IN int obj_type, IN cl_obj_t *p_obj )\r
1402 {\r
1403         bus_filter_t    *p_bfi;\r
1404         bus_filter_t    *matched=NULL;\r
1405 \r
1406         CL_ASSERT((obj_type == BFI_PORT_MGR_OBJ) || (obj_type == BFI_IOU_MGR_OBJ));\r
1407 \r
1408         lock_control_event();\r
1409 \r
1410         for(p_bfi=g_bus_filters; p_bfi < &g_bus_filters[MAX_BUS_FILTERS]; p_bfi++) {\r
1411 \r
1412                 if ( !p_bfi->p_bus_ext )\r
1413                         continue;\r
1414 \r
1415                 if ( obj_type == BFI_PORT_MGR_OBJ ) {\r
1416                         if ( p_obj == p_bfi->p_port_mgr_obj ) {\r
1417                                 matched = p_bfi;\r
1418                                 break;\r
1419                         }\r
1420                 }\r
1421                 else {\r
1422                         if ( p_obj == p_bfi->p_iou_mgr_obj ) {\r
1423                                 matched = p_bfi;\r
1424                                 break;\r
1425                         }\r
1426                 }\r
1427         }\r
1428         unlock_control_event();\r
1429 \r
1430         BUS_PRINT( BUS_DBG_PNP,\r
1431                                 ("%s() cl_obj %p type %s_MGR_OBJ --> bfi[%d] %p\n",\r
1432                                 __FUNCTION__,p_obj,\r
1433                                 (obj_type == BFI_PORT_MGR_OBJ ? "PORT": "IOU"),\r
1434                                 (matched ? (matched - g_bus_filters) : (-1)), matched ) );\r
1435 \r
1436         return matched;\r
1437 }\r
1438 \r
1439 /*\r
1440  * find a bus filter instance given an HCA guid.\r
1441  * BFIs are bound to GUIDs in fdo_start().\r
1442  */\r
1443 \r
1444 bus_filter_t *\r
1445 get_bfi_by_ca_guid( IN net64_t ca_guid )\r
1446 {\r
1447         bus_filter_t    *p_bfi;\r
1448         bus_filter_t    *matched=NULL;\r
1449 \r
1450         if ( ca_guid == 0ULL )\r
1451         {\r
1452                 matched = g_bus_filters;\r
1453                 BUS_PRINT( BUS_DBG_PNP, ("%s() ERR guid %I64x -> bfi[0] %p\n",\r
1454                                                                 __FUNCTION__, ca_guid, matched) );\r
1455                 CL_ASSERT( ca_guid );\r
1456                 return matched;\r
1457         }\r
1458 \r
1459         lock_control_event();\r
1460 \r
1461         for(p_bfi=g_bus_filters; p_bfi < &g_bus_filters[MAX_BUS_FILTERS]; p_bfi++)\r
1462         {\r
1463                 if ( !p_bfi->p_bus_ext )\r
1464                         continue;\r
1465 \r
1466                 if ( ca_guid == p_bfi->ca_guid )\r
1467                 {\r
1468                         matched = p_bfi;\r
1469                         break;\r
1470                 }\r
1471         }\r
1472         unlock_control_event();\r
1473 \r
1474 #if DBG\r
1475         if ( !matched )\r
1476         {\r
1477                 BUS_PRINT( BUS_DBG_PNP, ("No Match ca_guid 0x%I64x -> bfi[%d] %p\n",\r
1478                                                                         ca_guid, -1, matched ) );\r
1479         }\r
1480 #endif\r
1481         return matched;\r
1482 }\r
1483 \r
1484 \r
1485 bus_filter_t *\r
1486 alloc_bfi( IN DRIVER_OBJECT  *p_driver_obj, OUT int *p_instance_count )\r
1487 {\r
1488         bus_filter_t    *p_bfi;\r
1489         bus_filter_t    *matched=NULL;\r
1490 \r
1491     /* Using unsafe function so that the IRQL remains at PASSIVE_LEVEL.\r
1492      * IoCreateDeviceSecure & IoCreateSymbolicLink must be called at\r
1493      * PASSIVE_LEVEL.\r
1494          */\r
1495         lock_control_event();\r
1496 \r
1497         // find 1st unused bfi slot.\r
1498         for(p_bfi=g_bus_filters; p_bfi < &g_bus_filters[MAX_BUS_FILTERS]; p_bfi++)\r
1499         {\r
1500                 if ( !p_bfi->p_bus_ext )\r
1501                 {\r
1502                         /* temp setting until 'real' p_bus_ext is alloc; see bus_add_device.\r
1503                          * If p_bus_ext is ! 0, then bfi slot is allocated, although it\r
1504                          * may not yet have a bound CA guid; set set_get_\r
1505                          */\r
1506                         p_bfi->p_bus_ext = (bus_fdo_ext_t*)p_driver_obj;\r
1507                         matched = p_bfi;\r
1508                         *p_instance_count = ++g_bfi_InstanceCount; // record in-use\r
1509                         break;\r
1510                 }\r
1511         }\r
1512         unlock_control_event();\r
1513 \r
1514 #if DBG\r
1515         RtlStringCbPrintfA ( p_bfi->whoami,\r
1516                                                  sizeof(p_bfi->whoami),\r
1517                                                  "bfi-%d",\r
1518                                                  (g_bfi_InstanceCount - 1) );\r
1519 \r
1520         p_bfi->magic = BFI_MAGIC;\r
1521 #endif\r
1522 \r
1523         BUS_PRINT( BUS_DBG_PNP, ("%s() %s %p\n",\r
1524                                 __FUNCTION__, (matched ? matched->whoami:"Nobody"), matched) );\r
1525 \r
1526         return matched;\r
1527 }\r
1528 \r
1529 \r
1530 int\r
1531 free_bfi( IN  bus_filter_t  *p_bfi )\r
1532 {\r
1533         int     remaining;\r
1534 \r
1535         lock_control_event();\r
1536         p_bfi->p_bus_ext = NULL;\r
1537         p_bfi->ca_guid = 0ULL;\r
1538         remaining = --g_bfi_InstanceCount; // one less bfi in-use\r
1539         unlock_control_event();\r
1540         \r
1541         return remaining;\r
1542 }\r
1543 \r
1544 int\r
1545 get_bfi_count( void )\r
1546 {\r
1547         int     ic;\r
1548 \r
1549         lock_control_event();\r
1550         ic = g_bfi_InstanceCount;\r
1551         unlock_control_event();\r
1552         \r
1553         return ic;\r
1554 }\r
1555 \r
1556 #if DBG\r
1557 char *get_obj_state_str(cl_state_t state)\r
1558 {\r
1559         switch( state ) {\r
1560           case CL_UNINITIALIZED:\r
1561                 return "UNINITIALIZED";\r
1562           case CL_INITIALIZED:\r
1563                 return "INITIALIZED";\r
1564           case CL_DESTROYING:\r
1565                 return "DESTROYING";\r
1566           case CL_DESTROYED:\r
1567                 return "DESTROYED";\r
1568           default:\r
1569                 break;\r
1570         }\r
1571         return "Err - Bad obj state";\r
1572 }\r
1573 #endif\r
1574 \r