c1f8e789897361828e60f926344829f364009a63
[mirror/winof/.git] / core / bus / kernel / bus_driver.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  * Provides the driver entry points for the InfiniBand Bus Driver.\r
36  */\r
37 \r
38 #include <complib/cl_types.h>\r
39 #include "bus_driver.h"\r
40 #include "bus_pnp.h"\r
41 #include "al_mgr.h"\r
42 #include "al_dev.h"\r
43 #include "al_debug.h"\r
44 #include <complib/cl_init.h>\r
45 \r
46 \r
47 #if defined(EVENT_TRACING)\r
48 #ifdef offsetof\r
49 #undef offsetof\r
50 #endif\r
51 #include "bus_driver.tmh"\r
52 #endif\r
53 \r
54 \r
55 #define DEFAULT_NODE_DESC       "OpenIB Windows® Host"\r
56 \r
57 \r
58 char    node_desc[IB_NODE_DESCRIPTION_SIZE];\r
59 \r
60 bus_globals_t   bus_globals = {\r
61         BUS_DBG_ERROR,\r
62         TRUE,\r
63         NULL,\r
64         NULL\r
65 };\r
66 \r
67 static void\r
68 __read_machine_name( void );\r
69 \r
70 static NTSTATUS\r
71 __read_registry(\r
72         IN                              UNICODE_STRING* const           p_Param_Path );\r
73 \r
74 static NTSTATUS\r
75 bus_drv_open(\r
76         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
77         IN                              IRP                                                     *p_irp );\r
78 \r
79 static NTSTATUS\r
80 bus_drv_cleanup(\r
81         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
82         IN                              IRP                                                     *p_irp );\r
83 \r
84 static NTSTATUS\r
85 bus_drv_close(\r
86         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
87         IN                              IRP                                                     *p_irp );\r
88 \r
89 static NTSTATUS\r
90 bus_drv_ioctl(\r
91         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
92         IN                              IRP                                                     *p_irp );\r
93 \r
94 /***f* InfiniBand Bus Driver/bus_drv_sysctl\r
95 * NAME\r
96 *       bus_drv_sysctl\r
97 *\r
98 * DESCRIPTION\r
99 *       Entry point for handling WMI IRPs.\r
100 *\r
101 * SYNOPSIS\r
102 */\r
103 static NTSTATUS\r
104 bus_drv_sysctl(\r
105         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
106         IN                              IRP                                                     *p_irp );\r
107 /**********/\r
108 \r
109 static void\r
110 bus_drv_unload(\r
111         IN                              DRIVER_OBJECT                           *p_driver_obj );\r
112 \r
113 NTSTATUS\r
114 DriverEntry(\r
115         IN                              DRIVER_OBJECT                           *p_driver_obj,\r
116         IN                              UNICODE_STRING                          *p_registry_path );\r
117 \r
118 \r
119 #ifdef ALLOC_PRAGMA\r
120 #pragma alloc_text (INIT, DriverEntry)\r
121 #pragma alloc_text (INIT, __read_machine_name)\r
122 #pragma alloc_text (INIT, __read_registry)\r
123 #pragma alloc_text (PAGE, bus_drv_unload)\r
124 #pragma alloc_text (PAGE, bus_drv_open)\r
125 #pragma alloc_text (PAGE, bus_drv_close)\r
126 #pragma alloc_text (PAGE, bus_drv_ioctl)\r
127 #pragma alloc_text (PAGE_PNP, bus_drv_sysctl)\r
128 #endif\r
129 \r
130 \r
131 static void\r
132 __read_machine_name( void )\r
133 {\r
134         NTSTATUS                                        status;\r
135         /* Remember the terminating entry in the table below. */\r
136         RTL_QUERY_REGISTRY_TABLE        table[2];\r
137         UNICODE_STRING                          hostNamePath;\r
138         UNICODE_STRING                          hostNameW;\r
139         ANSI_STRING                                     hostName;\r
140 \r
141         BUS_ENTER( BUS_DBG_DRV );\r
142 \r
143         /* Get the host name. */\r
144         RtlInitUnicodeString( &hostNamePath, L"ComputerName\\ComputerName" );\r
145         RtlInitUnicodeString( &hostNameW, NULL );\r
146 \r
147         /*\r
148          * Clear the table.  This clears all the query callback pointers,\r
149          * and sets up the terminating table entry.\r
150          */\r
151         cl_memclr( table, sizeof(table) );\r
152         cl_memclr( node_desc, sizeof(node_desc) );\r
153 \r
154         /* Setup the table entries. */\r
155         table[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;\r
156         table[0].Name = L"ComputerName";\r
157         table[0].EntryContext = &hostNameW;\r
158         table[0].DefaultType = REG_SZ;\r
159         table[0].DefaultData = &hostNameW;\r
160         table[0].DefaultLength = 0;\r
161 \r
162         /* Have at it! */\r
163         status = RtlQueryRegistryValues( RTL_REGISTRY_CONTROL, \r
164                 hostNamePath.Buffer, table, NULL, NULL );\r
165         if( NT_SUCCESS( status ) )\r
166         {\r
167                 /* Convert the UNICODE host name to UTF-8 (ASCII). */\r
168                 hostName.Length = 0;\r
169                 hostName.MaximumLength = sizeof(node_desc);\r
170                 hostName.Buffer = node_desc;\r
171                 status = RtlUnicodeStringToAnsiString( &hostName, &hostNameW, FALSE );\r
172                 RtlFreeUnicodeString( &hostNameW );\r
173         }\r
174         else\r
175         {\r
176                 BUS_TRACE(BUS_DBG_ERROR , ("Failed to get host name.\n") );\r
177                 /* Use the default name... */\r
178                 RtlStringCbCopyNA( node_desc, sizeof(node_desc),\r
179                         DEFAULT_NODE_DESC, sizeof(DEFAULT_NODE_DESC) );\r
180         }\r
181 \r
182         BUS_ENTER( BUS_DBG_DRV );\r
183 }\r
184 \r
185 \r
186 static NTSTATUS\r
187 __read_registry(\r
188         IN                              UNICODE_STRING* const           p_registry_path )\r
189 {\r
190         NTSTATUS                                        status;\r
191         /* Remember the terminating entry in the table below. */\r
192         RTL_QUERY_REGISTRY_TABLE        table[9];\r
193         UNICODE_STRING                          param_path;\r
194 \r
195         BUS_ENTER( BUS_DBG_DRV );\r
196 \r
197         __read_machine_name();\r
198 \r
199         RtlInitUnicodeString( &param_path, NULL );\r
200         param_path.MaximumLength = p_registry_path->Length + \r
201                 sizeof(L"\\Parameters");\r
202         param_path.Buffer = cl_zalloc( param_path.MaximumLength );\r
203         if( !param_path.Buffer )\r
204         {\r
205                 BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
206                         ("Failed to allocate parameters path buffer.\n") );\r
207                 return STATUS_INSUFFICIENT_RESOURCES;\r
208         }\r
209 \r
210         RtlAppendUnicodeStringToString( &param_path, p_registry_path );\r
211         RtlAppendUnicodeToString( &param_path, L"\\Parameters" );\r
212 \r
213         /*\r
214          * Clear the table.  This clears all the query callback pointers,\r
215          * and sets up the terminating table entry.\r
216          */\r
217         cl_memclr( table, sizeof(table) );\r
218 \r
219         /* Setup the table entries. */\r
220         table[0].Flags = RTL_QUERY_REGISTRY_DIRECT;\r
221         table[0].Name = L"ReportPortNIC";\r
222         table[0].EntryContext = &bus_globals.b_report_port_nic;\r
223         table[0].DefaultType = REG_DWORD;\r
224         table[0].DefaultData = &bus_globals.b_report_port_nic;\r
225         table[0].DefaultLength = sizeof(ULONG);\r
226 \r
227         table[1].Flags = RTL_QUERY_REGISTRY_DIRECT;\r
228         table[1].Name = L"DebugFlags";\r
229         table[1].EntryContext = &bus_globals.dbg_lvl;\r
230         table[1].DefaultType = REG_DWORD;\r
231         table[1].DefaultData = &bus_globals.dbg_lvl;\r
232         table[1].DefaultLength = sizeof(ULONG);\r
233 \r
234         table[2].Flags = RTL_QUERY_REGISTRY_DIRECT;\r
235         table[2].Name = L"IbalDebugLevel";\r
236         table[2].EntryContext = &g_al_dbg_level;\r
237         table[2].DefaultType = REG_DWORD;\r
238         table[2].DefaultData = &g_al_dbg_level;\r
239         table[2].DefaultLength = sizeof(ULONG);\r
240 \r
241         table[3].Flags = RTL_QUERY_REGISTRY_DIRECT;\r
242         table[3].Name = L"IbalDebugFlags";\r
243         table[3].EntryContext = &g_al_dbg_flags;\r
244         table[3].DefaultType = REG_DWORD;\r
245         table[3].DefaultData = &g_al_dbg_flags;\r
246         table[3].DefaultLength = sizeof(ULONG);\r
247         \r
248 \r
249         table[4].Flags = RTL_QUERY_REGISTRY_DIRECT;\r
250         table[4].Name = L"SmiPollInterval";\r
251         table[4].EntryContext = &g_smi_poll_interval;\r
252         table[4].DefaultType = REG_DWORD;\r
253         table[4].DefaultData = &g_smi_poll_interval;\r
254         table[4].DefaultLength = sizeof(ULONG);\r
255 \r
256         table[5].Flags = RTL_QUERY_REGISTRY_DIRECT;\r
257         table[5].Name = L"IocQueryTimeout";\r
258         table[5].EntryContext = &g_ioc_query_timeout;\r
259         table[5].DefaultType = REG_DWORD;\r
260         table[5].DefaultData = &g_ioc_query_timeout;\r
261         table[5].DefaultLength = sizeof(ULONG);\r
262 \r
263         table[6].Flags = RTL_QUERY_REGISTRY_DIRECT;\r
264         table[6].Name = L"IocQueryRetries";\r
265         table[6].EntryContext = &g_ioc_query_retries;\r
266         table[6].DefaultType = REG_DWORD;\r
267         table[6].DefaultData = &g_ioc_query_retries;\r
268         table[6].DefaultLength = sizeof(ULONG);\r
269 \r
270         table[7].Flags = RTL_QUERY_REGISTRY_DIRECT;\r
271         table[7].Name = L"IocPollInterval";\r
272         table[7].EntryContext = &g_ioc_poll_interval;\r
273         table[7].DefaultType = REG_DWORD;\r
274         table[7].DefaultData = &g_ioc_poll_interval;\r
275         table[7].DefaultLength = sizeof(ULONG);\r
276 \r
277         /* Have at it! */\r
278         status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, \r
279                 param_path.Buffer, table, NULL, NULL );\r
280 \r
281 #if DBG\r
282         if( g_al_dbg_flags & AL_DBG_ERR )\r
283                 g_al_dbg_flags |= CL_DBG_ERROR;\r
284 #endif\r
285 \r
286         BUS_TRACE(BUS_DBG_DRV ,\r
287                         ("debug level %d debug flags 0x%.8x\n",\r
288                         g_al_dbg_level,\r
289                         g_al_dbg_flags));\r
290 \r
291         cl_free( param_path.Buffer );\r
292         BUS_EXIT( BUS_DBG_DRV );\r
293         return status;\r
294 }\r
295 \r
296 \r
297 static NTSTATUS\r
298 bus_drv_open(\r
299         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
300         IN                              IRP                                                     *p_irp )\r
301 {\r
302         BUS_ENTER( BUS_DBG_DRV );\r
303 \r
304         UNUSED_PARAM( p_dev_obj );\r
305 \r
306         CL_ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );\r
307 \r
308         /* We always succeed file handles creation. */\r
309         p_irp->IoStatus.Status = STATUS_SUCCESS;\r
310         p_irp->IoStatus.Information = 0;\r
311         IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
312 \r
313         BUS_EXIT( BUS_DBG_DRV );\r
314         return STATUS_SUCCESS;\r
315 }\r
316 \r
317 \r
318 static NTSTATUS\r
319 bus_drv_cleanup(\r
320         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
321         IN                              IRP                                                     *p_irp )\r
322 {\r
323         NTSTATUS                        status;\r
324 \r
325         BUS_ENTER( BUS_DBG_DRV );\r
326 \r
327         UNUSED_PARAM( p_dev_obj );\r
328 \r
329         CL_ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );\r
330 \r
331         /*\r
332          * Note that we don't acquire the remove and stop lock on close to allow\r
333          * applications to close the device when the locks are already held.\r
334          */\r
335         status = cl_to_ntstatus( al_dev_close( p_irp ) );\r
336 \r
337         /* Complete the IRP. */\r
338         p_irp->IoStatus.Status = status;\r
339         p_irp->IoStatus.Information = 0;\r
340         IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
341 \r
342         BUS_EXIT( BUS_DBG_DRV );\r
343         return status;\r
344 }\r
345 \r
346 \r
347 static NTSTATUS\r
348 bus_drv_close(\r
349         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
350         IN                              IRP                                                     *p_irp )\r
351 {\r
352         UNUSED_PARAM( p_dev_obj );\r
353 \r
354         p_irp->IoStatus.Status = STATUS_SUCCESS;\r
355         p_irp->IoStatus.Information = 0;\r
356         IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
357 \r
358         return STATUS_SUCCESS;\r
359 }\r
360 \r
361 \r
362 static NTSTATUS\r
363 bus_drv_ioctl(\r
364         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
365         IN                              IRP                                                     *p_irp )\r
366 {\r
367         NTSTATUS                        status;\r
368         bus_fdo_ext_t           *p_ext;\r
369         PIO_STACK_LOCATION      p_io_stack;\r
370 \r
371         BUS_ENTER( BUS_DBG_DRV );\r
372 \r
373         /* Get the extension. */\r
374         p_ext = p_dev_obj->DeviceExtension;\r
375 \r
376         /* Get the stack location. */\r
377         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
378 \r
379         /* Acquire the stop lock. */\r
380         status = IoAcquireRemoveLock( &p_ext->cl_ext.stop_lock, p_irp );\r
381         if( !NT_SUCCESS( status ) )\r
382         {\r
383                 p_irp->IoStatus.Status = status;\r
384                 p_irp->IoStatus.Information = 0;\r
385                 IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
386                 BUS_EXIT( BUS_DBG_DRV );\r
387                 return status;\r
388         }\r
389 \r
390         /* Acquire the remove lock. */\r
391         status = IoAcquireRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
392         if( !NT_SUCCESS( status ) )\r
393         {\r
394                 IoReleaseRemoveLock( &p_ext->cl_ext.stop_lock, p_irp );\r
395                 p_irp->IoStatus.Status = status;\r
396                 p_irp->IoStatus.Information = 0;\r
397                 IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
398                 BUS_EXIT( BUS_DBG_DRV );\r
399                 return status;\r
400         }\r
401         \r
402         status = cl_to_ntstatus( al_dev_ioctl( p_irp ) );\r
403         \r
404         /* Only pass down if not handled and not PDO device. */\r
405         if( status == STATUS_INVALID_DEVICE_REQUEST && p_ext->cl_ext.p_next_do )\r
406         {\r
407                 IoSkipCurrentIrpStackLocation( p_irp );\r
408                 status = IoCallDriver( p_ext->cl_ext.p_next_do, p_irp );\r
409         }\r
410 \r
411         /* Release the remove and stop locks. */\r
412         IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
413         IoReleaseRemoveLock( &p_ext->cl_ext.stop_lock, p_irp );\r
414 \r
415         BUS_EXIT( BUS_DBG_DRV );\r
416         return status;\r
417 }\r
418 \r
419 \r
420 static NTSTATUS\r
421 bus_drv_sysctl(\r
422         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
423         IN                              IRP                                                     *p_irp )\r
424 {\r
425         NTSTATUS                status;\r
426         bus_fdo_ext_t   *p_ext;\r
427 \r
428         BUS_ENTER( BUS_DBG_DRV );\r
429 \r
430         CL_ASSERT( p_dev_obj );\r
431         CL_ASSERT( p_irp );\r
432 \r
433         p_ext = p_dev_obj->DeviceExtension;\r
434 \r
435         if( p_ext->cl_ext.p_next_do )\r
436         {\r
437                 IoSkipCurrentIrpStackLocation( p_irp );\r
438                 status = IoCallDriver( p_ext->cl_ext.p_next_do, p_irp );\r
439         }\r
440         else\r
441         {\r
442                 status = p_irp->IoStatus.Status;\r
443                 IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
444         }\r
445 \r
446         BUS_EXIT( BUS_DBG_DRV );\r
447         return status;\r
448 }\r
449 \r
450 \r
451 static void\r
452 bus_drv_unload(\r
453         IN                              DRIVER_OBJECT                           *p_driver_obj )\r
454 {\r
455         BUS_ENTER( BUS_DBG_DRV );\r
456 \r
457         UNUSED_PARAM( p_driver_obj );\r
458 \r
459         CL_DEINIT;\r
460 \r
461 #if defined(EVENT_TRACING)\r
462         WPP_CLEANUP(p_driver_obj);\r
463 #endif\r
464 \r
465         BUS_EXIT( BUS_DBG_DRV );\r
466         \r
467 }\r
468 \r
469 \r
470 NTSTATUS\r
471 DriverEntry(\r
472         IN                              DRIVER_OBJECT                           *p_driver_obj,\r
473         IN                              UNICODE_STRING                          *p_registry_path )\r
474 {\r
475         NTSTATUS                        status;\r
476 \r
477         BUS_ENTER( BUS_DBG_DRV );\r
478 \r
479 #if defined(EVENT_TRACING)\r
480         WPP_INIT_TRACING(p_driver_obj ,p_registry_path);\r
481 #endif\r
482 \r
483         status = CL_INIT;\r
484         if( !NT_SUCCESS(status) )\r
485         {\r
486                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
487                         ("cl_init returned %08X.\n", status) );\r
488                 return status;\r
489         }\r
490 \r
491         /* Store the driver object pointer in the global parameters. */\r
492         bus_globals.p_driver_obj = p_driver_obj;\r
493 \r
494         /* Get the registry values. */\r
495         status = __read_registry( p_registry_path );\r
496         if( !NT_SUCCESS(status) )\r
497         {\r
498                 CL_DEINIT;\r
499                 BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
500                         ("__read_registry returned %08x.\n", status) );\r
501                 return status;\r
502         }\r
503 \r
504         /* Setup the entry points. */\r
505         p_driver_obj->MajorFunction[IRP_MJ_CREATE] = bus_drv_open;\r
506         p_driver_obj->MajorFunction[IRP_MJ_CLEANUP] = bus_drv_cleanup;\r
507         p_driver_obj->MajorFunction[IRP_MJ_CLOSE] = bus_drv_close;\r
508         p_driver_obj->MajorFunction[IRP_MJ_PNP] = cl_pnp;\r
509         p_driver_obj->MajorFunction[IRP_MJ_POWER] = cl_power;\r
510         p_driver_obj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = bus_drv_ioctl;\r
511         p_driver_obj->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = bus_drv_sysctl;\r
512         p_driver_obj->DriverUnload = bus_drv_unload;\r
513         p_driver_obj->DriverExtension->AddDevice = bus_add_device;\r
514 \r
515         BUS_EXIT( BUS_DBG_DRV );\r
516         return STATUS_SUCCESS;\r
517 }\r