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