[CORE] Expose vendor defined device in ibiou.
[mirror/winof/.git] / core / iou / kernel / iou_driver.c
1 /*\r
2  * Copyright (c) 2005 SilverStorm Technologies.  All rights reserved.\r
3  *\r
4  * This software is available to you under the OpenIB.org BSD license\r
5  * below:\r
6  *\r
7  *     Redistribution and use in source and binary forms, with or\r
8  *     without modification, are permitted provided that the following\r
9  *     conditions are met:\r
10  *\r
11  *      - Redistributions of source code must retain the above\r
12  *        copyright notice, this list of conditions and the following\r
13  *        disclaimer.\r
14  *\r
15  *      - Redistributions in binary form must reproduce the above\r
16  *        copyright notice, this list of conditions and the following\r
17  *        disclaimer in the documentation and/or other materials\r
18  *        provided with the distribution.\r
19  *\r
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
21  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
22  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
23  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
24  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
25  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
26  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
27  * SOFTWARE.\r
28  *\r
29  * $Id$\r
30  */\r
31 \r
32 \r
33 /*\r
34  * Provides the driver entry points for the InfiniBand I/O Unit Bus Driver.\r
35  */\r
36 \r
37 #include <complib/cl_types.h>\r
38 #include "iou_driver.h"\r
39 #if defined(EVENT_TRACING)\r
40 #ifdef offsetof\r
41 #undef offsetof\r
42 #endif\r
43 #include "iou_driver.tmh"\r
44 #endif\r
45 #include "iou_pnp.h"\r
46 #include "al_dev.h"\r
47 #include "iou_ioc_mgr.h"\r
48 #include <complib/cl_init.h>\r
49 #include <complib/cl_bus_ifc.h>\r
50 \r
51 iou_globals_t   iou_globals = {\r
52         NULL\r
53 };\r
54 \r
55 uint32_t                g_iou_dbg_level = TRACE_LEVEL_ERROR;\r
56 uint32_t                g_iou_dbg_flags = 0x00000fff;\r
57 \r
58 static NTSTATUS\r
59 __read_registry(\r
60         IN                              UNICODE_STRING* const           p_Param_Path );\r
61 \r
62 static NTSTATUS\r
63 iou_drv_open(\r
64         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
65         IN                              IRP                                                     *p_irp );\r
66 \r
67 static NTSTATUS\r
68 iou_drv_close(\r
69         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
70         IN                              IRP                                                     *p_irp );\r
71 \r
72 static NTSTATUS\r
73 iou_drv_cleanup(\r
74         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
75         IN                              IRP                                     *p_irp);\r
76 \r
77 static NTSTATUS\r
78 iou_drv_ioctl(\r
79         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
80         IN                              IRP                                                     *p_irp );\r
81 \r
82 /***f* InfiniBand Bus Driver/iou_sysctl\r
83 * NAME\r
84 *       iou_sysctl\r
85 *\r
86 * DESCRIPTION\r
87 *       Entry point for handling WMI IRPs.\r
88 *\r
89 * SYNOPSIS\r
90 */\r
91 static NTSTATUS\r
92 iou_sysctl(\r
93         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
94         IN                              IRP                                                     *p_irp );\r
95 \r
96 /**********/\r
97 \r
98 static void\r
99 iou_unload(\r
100         IN                              DRIVER_OBJECT                           *p_driver_obj );\r
101 \r
102 NTSTATUS\r
103 DriverEntry(\r
104         IN                              DRIVER_OBJECT                           *p_driver_obj,\r
105         IN                              UNICODE_STRING                          *p_registry_path );\r
106 \r
107 \r
108 static void     _free_child_device_list()\r
109 {\r
110         child_device_info_list_t *pDevList, *pDevList1;\r
111 \r
112         pDevList = iou_globals.p_device_list;\r
113 \r
114         while( pDevList )\r
115         {\r
116                 pDevList1 = pDevList->next_device_info;\r
117                 cl_free( pDevList );\r
118                 pDevList = pDevList1;\r
119         }\r
120 \r
121 }\r
122 \r
123 static NTSTATUS _build_child_device_list( PUNICODE_STRING p_param_path )\r
124 {\r
125         RTL_QUERY_REGISTRY_TABLE        table[2];\r
126         UNICODE_STRING                  keyPath;\r
127         UNICODE_STRING                  keyValue;\r
128         UNICODE_STRING                  child_name;\r
129         WCHAR                           *key_path_buffer;\r
130         WCHAR                           *key_value_buffer;\r
131         WCHAR                           *static_child_name;\r
132         NTSTATUS                        status;\r
133         uint32_t                        instanceid = 1;\r
134         HANDLE                          hParamKey = NULL;\r
135         UNICODE_STRING                  valuename;\r
136         ULONG                           sizeofbuf;\r
137         PVOID                           pBuf = NULL;\r
138         PKEY_VALUE_FULL_INFORMATION     pKeyVal = NULL;\r
139         uint64_t                        guid_val = 0;\r
140         OBJECT_ATTRIBUTES               objattr;\r
141         WCHAR                           *curChild;\r
142         child_device_info_list_t        *pPrevList, *pNewDevList;\r
143 \r
144         cl_memclr(  table, sizeof( table) );\r
145 \r
146         /* use hard-coded size 256 to make it simple*/\r
147         key_path_buffer = cl_zalloc( 256*sizeof( WCHAR )*3 ) ;\r
148 \r
149         if( !key_path_buffer )\r
150         {\r
151                 IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR ,( "Not enough memeory for key_path_buffer.\n" ) );\r
152                 status = STATUS_UNSUCCESSFUL;\r
153                 goto _build_child_device_list_exit;\r
154         }\r
155 \r
156         key_value_buffer = key_path_buffer + 256;\r
157         static_child_name = key_value_buffer + 256;\r
158 \r
159         RtlInitUnicodeString( &keyPath, NULL );\r
160         keyPath.MaximumLength = 256*sizeof( WCHAR );\r
161         keyPath.Buffer = key_path_buffer;\r
162 \r
163         RtlInitUnicodeString( &keyValue, NULL );\r
164         keyValue.MaximumLength = 256*sizeof( WCHAR );\r
165         keyValue.Buffer = key_value_buffer;\r
166 \r
167         RtlInitUnicodeString( &child_name, NULL );\r
168         child_name.MaximumLength = 256*sizeof( WCHAR );\r
169         child_name.Buffer = static_child_name;\r
170 \r
171 \r
172         RtlCopyUnicodeString( &keyPath, p_param_path );\r
173 \r
174         /* Setup the table entries. */\r
175         table[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND;\r
176         table[0].Name = L"StaticChild";\r
177         table[0].EntryContext = &child_name;\r
178         table[0].DefaultType = REG_NONE;\r
179 \r
180         status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, \r
181                 keyPath.Buffer, table, NULL, NULL );\r
182 \r
183         if( !NT_SUCCESS( status ) )\r
184         {\r
185                 if ( status == STATUS_INVALID_PARAMETER )\r
186                 {\r
187                         IOU_PRINT(TRACE_LEVEL_WARNING, IOU_DBG_ERROR, \r
188                                         ("Failed to read registry values\n") );\r
189                 }\r
190                 goto _build_child_device_list_exit;\r
191         }\r
192 \r
193         curChild = static_child_name;\r
194         pPrevList = iou_globals.p_device_list;\r
195         while( *curChild )\r
196         {\r
197                 RtlCopyUnicodeString( &keyPath, p_param_path );\r
198                 RtlAppendUnicodeToString( &keyPath, L"\\" );\r
199                 RtlAppendUnicodeToString( &keyPath, curChild );\r
200 \r
201                 pNewDevList = cl_zalloc( sizeof( child_device_info_list_t ) );\r
202                 if( !pNewDevList )\r
203                 {\r
204                         IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR, \r
205                                         ( "Not enough memeory for key_path_buffer.\n" ) );\r
206                         status = STATUS_UNSUCCESSFUL;\r
207                         goto _build_child_device_list_exit;\r
208                 }\r
209                 pNewDevList->next_device_info = NULL;\r
210 \r
211                 if( pPrevList == NULL )\r
212                 {\r
213                         iou_globals.p_device_list = pNewDevList;\r
214                 }\r
215                 else\r
216                 {\r
217                         pPrevList->next_device_info = pNewDevList;\r
218                 }\r
219 \r
220                 pPrevList = pNewDevList;\r
221 \r
222                 RtlInitUnicodeString( &keyValue, NULL );\r
223                 keyValue.MaximumLength = sizeof( pNewDevList->io_device_info.device_id );\r
224                 keyValue.Buffer = pNewDevList->io_device_info.device_id;\r
225 \r
226                 /* Setup the table entries. */\r
227                 table[0].Flags = RTL_QUERY_REGISTRY_DIRECT;\r
228                 table[0].Name = L"DeviceId";\r
229                 table[0].EntryContext = &keyValue; \r
230                 table[0].DefaultType = REG_NONE;\r
231 \r
232                 status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, \r
233                         keyPath.Buffer, table, NULL, NULL );\r
234                 if( !NT_SUCCESS( status ) )\r
235                 {\r
236                         IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR, \r
237                                         ( "Failed to read DeviceId.\n" ) );\r
238                         goto _build_child_device_list_exit;\r
239                 }\r
240                 pNewDevList->io_device_info.device_id_size = keyValue.Length + sizeof( WCHAR);\r
241 \r
242                 /* Get HardwareId*/\r
243                 RtlInitUnicodeString( &keyValue, NULL );\r
244                 keyValue.MaximumLength = sizeof( pNewDevList->io_device_info.hardware_id );\r
245                 keyValue.Buffer = pNewDevList->io_device_info.hardware_id;\r
246 \r
247                 /* Setup the table entries. */\r
248                 table[0].Flags = RTL_QUERY_REGISTRY_DIRECT;\r
249                 table[0].Name = L"HardwareId";\r
250                 table[0].EntryContext = &keyValue; \r
251                 table[0].DefaultType = REG_NONE;\r
252 \r
253                 status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, \r
254                         keyPath.Buffer, table, NULL, NULL );\r
255                 if( !NT_SUCCESS( status ) )\r
256                 {\r
257                         IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR ,\r
258                                         ( "Failed to read HardwareId.\n" ) );\r
259                         goto _build_child_device_list_exit;\r
260                 }\r
261                 pNewDevList->io_device_info.hardware_id_size = keyValue.Length + 2*sizeof( WCHAR );\r
262                 /* Get CompatibleId*/\r
263                 RtlInitUnicodeString( &keyValue, NULL );\r
264                 keyValue.MaximumLength = sizeof( pNewDevList->io_device_info.compatible_id );\r
265                 keyValue.Buffer = pNewDevList->io_device_info.compatible_id;\r
266                 /* Setup the table entries. */\r
267                 table[0].Flags = RTL_QUERY_REGISTRY_DIRECT;\r
268                 table[0].Name = L"CompatibleId";\r
269                 table[0].EntryContext = &keyValue; \r
270                 table[0].DefaultType = REG_NONE;\r
271 \r
272                 status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, \r
273                         keyPath.Buffer, table, NULL, NULL );\r
274                 if( !NT_SUCCESS( status ) )\r
275                 {\r
276                         IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR ,\r
277                                         ( "Failed to read CompatibleId.\n" ) );\r
278                         goto _build_child_device_list_exit;\r
279                 }\r
280                 pNewDevList->io_device_info.compatible_id_size = keyValue.Length + 2*sizeof( WCHAR ); //2 null\r
281 \r
282                 /* Get Description*/\r
283                 RtlInitUnicodeString( &keyValue, NULL );\r
284                 keyValue.MaximumLength = sizeof( pNewDevList->io_device_info.description );\r
285                 keyValue.Buffer = pNewDevList->io_device_info.description;\r
286 \r
287                 /* Setup the table entries. */\r
288                 table[0].Flags = RTL_QUERY_REGISTRY_DIRECT;\r
289                 table[0].Name = L"Description";\r
290                 table[0].EntryContext = &keyValue; \r
291                 table[0].DefaultType = REG_NONE;\r
292 \r
293                 status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, \r
294                         keyPath.Buffer, table, NULL, NULL );\r
295                 if( !NT_SUCCESS( status ) )\r
296                 {\r
297                         IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR, \r
298                                         ( "Failed to read Description.\n" ) );\r
299                         goto _build_child_device_list_exit;\r
300                 }\r
301 \r
302                 pNewDevList->io_device_info.description_size = keyValue.Length + sizeof( WCHAR );\r
303 \r
304                 if( ( pNewDevList->io_device_info.description_size > MAX_DEVICE_ID_LEN) ||\r
305                    ( pNewDevList->io_device_info.hardware_id_size > MAX_DEVICE_ID_LEN) ||\r
306                    ( pNewDevList->io_device_info.compatible_id_size > MAX_DEVICE_ID_LEN) ||\r
307                    ( pNewDevList->io_device_info.device_id_size > MAX_DEVICE_ID_LEN)\r
308                    )\r
309                 {\r
310                         IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR, \r
311                                         ( "Id or description size is too big.\n" ) );\r
312                         status = STATUS_UNSUCCESSFUL;\r
313                         goto _build_child_device_list_exit;\r
314                 }\r
315 \r
316                 InitializeObjectAttributes( &objattr, &keyPath, OBJ_KERNEL_HANDLE, NULL, NULL );\r
317 \r
318                 status = ZwOpenKey( &hParamKey, GENERIC_READ, &objattr );\r
319 \r
320                 if ( !NT_SUCCESS( status ) ) \r
321                 {\r
322                         IOU_PRINT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR, \r
323                                         ( "ZwOpenKey failed with status %u\n",status ) );\r
324                         goto _build_child_device_list_exit;\r
325                 }\r
326                         \r
327                 RtlInitUnicodeString( &valuename, L"IOCGUID" );\r
328                 status = ZwQueryValueKey( hParamKey, &valuename, KeyValueFullInformation, NULL, 0, &sizeofbuf );\r
329 \r
330                 if ( status == STATUS_BUFFER_OVERFLOW || status == STATUS_BUFFER_TOO_SMALL ) \r
331                 {\r
332                         pBuf = cl_zalloc( sizeofbuf );\r
333                 }\r
334 \r
335                 if ( !pBuf && !NT_SUCCESS( status ) ) \r
336                 {\r
337                         IOU_PRINT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR, \r
338                                         ( "Either ZwQueryValueKey failed with status %u" \r
339                                           "or cl_zalloc failed\n",status ) );\r
340                         goto _build_child_device_list_exit;\r
341                 }\r
342 \r
343                 status = ZwQueryValueKey( hParamKey, &valuename, KeyValueFullInformation, pBuf, sizeofbuf, &sizeofbuf );\r
344 \r
345                 if ( !NT_SUCCESS( status ) ) \r
346                 {\r
347                         IOU_PRINT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR, \r
348                                         ( "ZwQueryValueKey failed with status %u\n",status ) );\r
349                         goto _build_child_device_list_exit;                             \r
350                 }\r
351 \r
352                 pKeyVal = ( PKEY_VALUE_FULL_INFORMATION ) pBuf;\r
353 \r
354                 if ( pKeyVal->Type & REG_BINARY ) \r
355                 {\r
356                         memcpy( &guid_val, ( ( ( char * ) pBuf ) + pKeyVal->DataOffset ), sizeof( uint64_t ) );\r
357                         pNewDevList->io_device_info.ca_ioc_path.info.profile.ioc_guid = guid_val;\r
358                         guid_val = 0;\r
359                 } \r
360                 else \r
361                 {\r
362                         IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR, \r
363                                         ( "IOC GUID is not of REG_BINARY type\n" ) );\r
364                         goto _build_child_device_list_exit;                             \r
365                 }\r
366                 cl_free( pBuf );\r
367                 pBuf = NULL;\r
368 \r
369                 RtlInitUnicodeString( &valuename, L"CAGUID" );\r
370                 status = ZwQueryValueKey( hParamKey, &valuename, KeyValueFullInformation, NULL, 0, &sizeofbuf );\r
371 \r
372                 if ( status == STATUS_BUFFER_OVERFLOW || status == STATUS_BUFFER_TOO_SMALL ) \r
373                 {\r
374                         pBuf = cl_zalloc( sizeofbuf );\r
375                 }\r
376 \r
377                 if ( !pBuf && !NT_SUCCESS( status ) ) \r
378                 {\r
379                         IOU_PRINT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR, \r
380                                         ( "Either ZwQueryValueKey failed with status %u"\r
381                                           "or cl_zalloc failed\n",status ) );\r
382                         goto _build_child_device_list_exit;                             \r
383                 }\r
384 \r
385                 status = ZwQueryValueKey( hParamKey, &valuename, KeyValueFullInformation, pBuf, sizeofbuf, &sizeofbuf );\r
386 \r
387                 if ( !NT_SUCCESS( status ) ) \r
388                 {\r
389                         IOU_PRINT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR, \r
390                                         ( "ZwQueryValueKey failed with status %u\n",status ) );\r
391                         goto _build_child_device_list_exit;                             \r
392                 }\r
393 \r
394                 pKeyVal = ( PKEY_VALUE_FULL_INFORMATION ) pBuf;\r
395 \r
396                 if ( pKeyVal->Type & REG_BINARY ) \r
397                 {\r
398                         memcpy( &guid_val, ( ( ( char * ) pBuf ) + pKeyVal->DataOffset ), sizeof( uint64_t ) );\r
399                         pNewDevList->io_device_info.ca_ioc_path.ca_guid = guid_val;     \r
400                 } \r
401                 else \r
402                 {\r
403                         IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR, \r
404                                         ( "CA GUID is not of REG_BINARY type\n"));\r
405                         goto _build_child_device_list_exit;                             \r
406                 }\r
407 \r
408                 cl_free( pBuf);\r
409                 pBuf = NULL;\r
410 \r
411                 RtlInitUnicodeString( &valuename, L"InstanceId");\r
412                 status = ZwQueryValueKey( hParamKey, &valuename, KeyValueFullInformation, NULL, 0, &sizeofbuf );\r
413 \r
414                 if ( status == STATUS_BUFFER_OVERFLOW || status == STATUS_BUFFER_TOO_SMALL ) \r
415                 {\r
416                 pBuf = cl_zalloc( sizeofbuf );\r
417                 }\r
418 \r
419                 if ( !pBuf && !NT_SUCCESS( status ) ) \r
420                 {\r
421                         IOU_PRINT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR, \r
422                                         ( "Either ZwQueryValueKey failed with status %u" \r
423                                           "or cl_zalloc failed\n",status ) );\r
424                         goto _build_child_device_list_exit;                             \r
425                 }\r
426 \r
427                 status = ZwQueryValueKey( hParamKey, &valuename, KeyValueFullInformation, \r
428                                 pBuf, sizeofbuf, &sizeofbuf );\r
429 \r
430                 if ( !NT_SUCCESS( status ) ) \r
431                 {\r
432                         IOU_PRINT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR, \r
433                                         ( "ZwQueryValueKey failed with status %u\n",status ) );\r
434                         goto _build_child_device_list_exit;                             \r
435                 }\r
436 \r
437                 pKeyVal = ( PKEY_VALUE_FULL_INFORMATION ) pBuf;\r
438 \r
439                 memcpy( &instanceid, ( ( ( char * ) pBuf ) + pKeyVal->DataOffset ), sizeof( instanceid ) );\r
440                         pNewDevList->io_device_info.uniqueinstanceid = instanceid;\r
441 \r
442                 cl_free( pBuf );\r
443                 pBuf = NULL;\r
444                         \r
445                 ZwClose( hParamKey );\r
446                 hParamKey = NULL;\r
447 \r
448                 while( *curChild ) curChild++;\r
449                 curChild++;\r
450 \r
451         }\r
452 \r
453 \r
454 _build_child_device_list_exit:\r
455         if( key_path_buffer )\r
456         {\r
457                 cl_free( key_path_buffer );\r
458         }\r
459 \r
460         if( !NT_SUCCESS( status ) )\r
461         {\r
462                 _free_child_device_list();\r
463         }\r
464 \r
465         if ( hParamKey != NULL ) \r
466         {\r
467                 ZwClose( hParamKey );\r
468         }\r
469 \r
470         if ( pBuf ) \r
471         {\r
472                 cl_free( pBuf );\r
473         }\r
474 \r
475         return status;\r
476 }\r
477 \r
478 static NTSTATUS\r
479 __read_registry(\r
480         IN                              UNICODE_STRING* const           p_registry_path )\r
481 {\r
482         NTSTATUS                                        status;\r
483         /* Remember the terminating entry in the table below. */\r
484         RTL_QUERY_REGISTRY_TABLE        table[3];\r
485         UNICODE_STRING                          param_path;\r
486 \r
487         IOU_ENTER( IOU_DBG_DRV );\r
488 \r
489         RtlInitUnicodeString( &param_path, NULL );\r
490         param_path.MaximumLength = p_registry_path->Length + \r
491                 sizeof(L"\\Parameters");\r
492         param_path.Buffer = cl_zalloc( param_path.MaximumLength );\r
493         if( !param_path.Buffer )\r
494         {\r
495                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR,IOU_DBG_ERROR,\r
496                         ("Failed to allocate parameters path buffer.\n") );\r
497                 return STATUS_INSUFFICIENT_RESOURCES;\r
498         }\r
499 \r
500         RtlAppendUnicodeStringToString( &param_path, p_registry_path );\r
501         RtlAppendUnicodeToString( &param_path, L"\\Parameters" );\r
502 \r
503         /*\r
504          * Clear the table.  This clears all the query callback pointers,\r
505          * and sets up the terminating table entry.\r
506          */\r
507         cl_memclr( table, sizeof(table) );\r
508 \r
509         /* Setup the table entries. */\r
510         table[0].Flags = RTL_QUERY_REGISTRY_DIRECT;\r
511         table[0].Name = L"DebugLevel";\r
512         table[0].EntryContext = &g_iou_dbg_level;\r
513         table[0].DefaultType = REG_DWORD;\r
514         table[0].DefaultData = &g_iou_dbg_level;\r
515         table[0].DefaultLength = sizeof(ULONG);\r
516 \r
517         table[1].Flags = RTL_QUERY_REGISTRY_DIRECT;\r
518         table[1].Name = L"DebugFlags";\r
519         table[1].EntryContext = &g_iou_dbg_flags;\r
520         table[1].DefaultType = REG_DWORD;\r
521         table[1].DefaultData = &g_iou_dbg_flags;\r
522         table[1].DefaultLength = sizeof(ULONG);\r
523         /* Have at it! */\r
524         status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE,\r
525                 param_path.Buffer, table, NULL, NULL );\r
526 \r
527 #ifndef EVENT_TRACING\r
528         if( g_iou_dbg_flags & IOU_DBG_ERR )\r
529                 g_iou_dbg_flags |= CL_DBG_ERROR;\r
530 #endif\r
531 \r
532         if(!NT_SUCCESS( _build_child_device_list (&param_path) ) ){\r
533         IOU_PRINT( TRACE_LEVEL_INFORMATION, IOU_DBG_DRV,\r
534                          ( "Failed to create devices\n" ) );\r
535         }\r
536 \r
537 \r
538         IOU_PRINT( TRACE_LEVEL_INFORMATION, IOU_DBG_DRV,\r
539                 ("debug level %d debug flags 0x%.8x\n",\r
540                 g_iou_dbg_level,\r
541                 g_iou_dbg_flags) );\r
542 \r
543         cl_free( param_path.Buffer );\r
544         IOU_EXIT( IOU_DBG_DRV );\r
545         return status;\r
546 }\r
547 \r
548 static NTSTATUS\r
549 _create_child_ioc_device(\r
550         IN                              child_device_info_t     *p_child_dev )\r
551 {\r
552         child_device_info_list_t        *p_prev_list, *p_new_dev_list, *temp = NULL;\r
553         ca_ioc_map_t                    *p_ca_ioc_map;\r
554         ib_api_status_t                 ib_status;\r
555 \r
556         p_prev_list = iou_globals.p_device_list;\r
557 \r
558         p_ca_ioc_map = find_ca_ioc_map( p_child_dev->ca_ioc_path.ca_guid,\r
559                                         p_child_dev->ca_ioc_path.info.profile.ioc_guid );\r
560 \r
561         if ( p_ca_ioc_map == NULL ) \r
562         {\r
563                 return STATUS_INTERNAL_ERROR;\r
564         }\r
565 \r
566         p_new_dev_list = cl_zalloc( sizeof( child_device_info_list_t ) );\r
567 \r
568         if ( !p_new_dev_list ) \r
569         {\r
570                 IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR,\r
571                               ( "Insufficient Memory\n" ) );\r
572                 return STATUS_INSUFFICIENT_RESOURCES;\r
573         }\r
574 \r
575         p_new_dev_list->io_device_info = *p_child_dev;\r
576         p_new_dev_list->next_device_info = NULL;\r
577 \r
578         if( p_prev_list == NULL ) \r
579         {\r
580                 iou_globals.p_device_list = p_new_dev_list;\r
581         } \r
582         else \r
583         {\r
584                 temp = p_prev_list->next_device_info;\r
585                 p_prev_list->next_device_info = p_new_dev_list;\r
586         }\r
587         p_new_dev_list->next_device_info = temp;\r
588         \r
589         ib_status = _create_ioc_pdo( &p_new_dev_list->io_device_info, p_ca_ioc_map );\r
590 \r
591         if ( ib_status != IB_SUCCESS ) \r
592         {\r
593                 IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR,\r
594                               ( "PDO creation for IOC failed\n" ) );\r
595                 cl_free( p_new_dev_list );\r
596                 return STATUS_INTERNAL_ERROR;\r
597         }\r
598 \r
599         return STATUS_SUCCESS;\r
600\r
601 \r
602 static ULONG\r
603 _build_ca_ioc_list( ca_ioc_info_t       *p_info )\r
604 {\r
605         cl_list_item_t  *p_item;\r
606         ca_ioc_map_t    *p_map;\r
607 \r
608         p_item = cl_qlist_head( &iou_globals.ca_ioc_map_list );\r
609 \r
610         while ( p_item != cl_qlist_end( &iou_globals.ca_ioc_map_list ) ) \r
611         {\r
612                 p_map = ( ca_ioc_map_t  *) p_item;\r
613                 p_info->ca_guid = p_map->ca_guid;\r
614                 p_info->info = p_map->info;\r
615                 cl_memcpy( p_info->svc_entry_array, p_map->svc_entry_array, \r
616                         sizeof( p_map->svc_entry_array ) );\r
617 \r
618                 p_item = cl_qlist_next( p_item );\r
619                 p_info++;\r
620         }\r
621 \r
622         return ( (ULONG) (sizeof(ca_ioc_info_t)*cl_qlist_count( &iou_globals.ca_ioc_map_list )) );\r
623 }\r
624 \r
625 static NTSTATUS\r
626 iou_drv_open(\r
627         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
628         IN                              IRP                                                     *p_irp )\r
629 {\r
630         IOU_ENTER( IOU_DBG_DRV );\r
631 \r
632         UNUSED_PARAM( p_dev_obj );\r
633 \r
634         CL_ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );\r
635 \r
636         /* We always succeed file handles creation. */\r
637         p_irp->IoStatus.Status = STATUS_SUCCESS;\r
638         p_irp->IoStatus.Information = 0;\r
639         IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
640 \r
641         IOU_EXIT( IOU_DBG_DRV );\r
642         return STATUS_SUCCESS;\r
643         \r
644 }\r
645 \r
646 static NTSTATUS\r
647 iou_drv_close(\r
648         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
649         IN                              IRP                                                     *p_irp )\r
650 {\r
651         UNUSED_PARAM( p_dev_obj );\r
652 \r
653         p_irp->IoStatus.Status = STATUS_SUCCESS;\r
654         p_irp->IoStatus.Information = 0;\r
655         IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
656 \r
657         return STATUS_SUCCESS;  \r
658 }\r
659 \r
660 static NTSTATUS\r
661 iou_drv_cleanup(\r
662         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
663         IN                              IRP                                     *p_irp)\r
664 {\r
665         IOU_ENTER( IOU_DBG_DRV );\r
666 \r
667         UNUSED_PARAM( p_dev_obj );\r
668 \r
669         CL_ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );\r
670 \r
671         /*\r
672          * Note that we don't acquire the remove and stop lock on close to allow\r
673          * applications to close the device when the locks are already held.\r
674          */\r
675 \r
676         /* Complete the IRP. */\r
677         p_irp->IoStatus.Status = STATUS_SUCCESS;\r
678         p_irp->IoStatus.Information = 0;\r
679         IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
680 \r
681         IOU_EXIT( IOU_DBG_DRV );\r
682         return STATUS_SUCCESS;\r
683 }\r
684 \r
685 static NTSTATUS\r
686 iou_drv_ioctl(\r
687         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
688         IN                              IRP                                                     *p_irp )\r
689 {\r
690         NTSTATUS                status = STATUS_SUCCESS;\r
691         PIO_STACK_LOCATION      p_io_stack;\r
692         ULONG                   controlcode, n_bytes;\r
693         size_t                  n_iocs;\r
694         ca_ioc_info_t           *p_ca_ioc_info;\r
695         child_device_info_t     *p_child_dev;\r
696 \r
697         IOU_ENTER( IOU_DBG_DRV );\r
698         CL_ASSERT( p_dev_obj );\r
699         CL_ASSERT( p_irp );\r
700         UNUSED_PARAM( p_dev_obj );\r
701 \r
702         /* Get the stack location. */\r
703         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
704         controlcode = p_io_stack->Parameters.DeviceIoControl.IoControlCode;\r
705         p_irp->IoStatus.Information = 0;\r
706 \r
707         switch ( controlcode ) \r
708         {\r
709                 case UAL_IOC_DEVICE_CREATE:\r
710                         p_child_dev = p_irp->AssociatedIrp.SystemBuffer;\r
711                         \r
712                         if ( sizeof( child_device_info_t) > \r
713                                 ( p_io_stack->Parameters.DeviceIoControl.\r
714                                   InputBufferLength ) ) \r
715                         {\r
716                                 status = STATUS_BUFFER_TOO_SMALL;\r
717                         } \r
718                         else \r
719                         {\r
720                                 status = _create_child_ioc_device( p_child_dev );\r
721                         }\r
722                         break;\r
723 \r
724                 case UAL_IOC_LIST:\r
725                         p_ca_ioc_info = p_irp->AssociatedIrp.SystemBuffer;\r
726                         cl_mutex_acquire( &iou_globals.list_mutex );\r
727                         n_iocs = cl_qlist_count( &iou_globals.ca_ioc_map_list );\r
728 \r
729                         if ( n_iocs*sizeof( ca_ioc_info_t) <= \r
730                                 p_io_stack->Parameters.DeviceIoControl.\r
731                                 OutputBufferLength )\r
732                         {\r
733                                 n_bytes = _build_ca_ioc_list( p_ca_ioc_info );\r
734                                 p_irp->IoStatus.Information = n_bytes;\r
735                                 status = STATUS_SUCCESS;\r
736                         } \r
737                         else \r
738                         {\r
739                                 status = STATUS_BUFFER_TOO_SMALL;\r
740                         }\r
741 \r
742                         cl_mutex_release( &iou_globals.list_mutex );\r
743 \r
744                         break;\r
745                 default:\r
746                         status = STATUS_INVALID_DEVICE_REQUEST;\r
747                         break;\r
748         }\r
749 \r
750         p_irp->IoStatus.Status = status;\r
751         IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
752         return status;\r
753 }\r
754 \r
755 static NTSTATUS\r
756 iou_sysctl(\r
757         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
758         IN                              IRP                                                     *p_irp )\r
759 {\r
760         NTSTATUS                status;\r
761         cl_pnp_po_ext_t *p_ext;\r
762 \r
763         IOU_ENTER( IOU_DBG_DRV );\r
764 \r
765         CL_ASSERT( p_dev_obj );\r
766         CL_ASSERT( p_irp );\r
767 \r
768         p_ext = p_dev_obj->DeviceExtension;\r
769 \r
770         if( p_ext->p_next_do )\r
771         {\r
772                 IoSkipCurrentIrpStackLocation( p_irp );\r
773                 status = IoCallDriver( p_ext->p_next_do, p_irp );\r
774         }\r
775         else\r
776         {\r
777                 status = p_irp->IoStatus.Status;\r
778                 IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
779         }\r
780 \r
781         IOU_EXIT( IOU_DBG_DRV );\r
782         return status;\r
783 }\r
784 \r
785 static void\r
786 iou_unload(\r
787         IN                              DRIVER_OBJECT                           *p_driver_obj )\r
788 {\r
789         UNICODE_STRING  dos_name;\r
790 \r
791         IOU_ENTER( IOU_DBG_DRV );\r
792 \r
793 #if defined(EVENT_TRACING)\r
794         WPP_CLEANUP( p_driver_obj );\r
795 #else\r
796         UNUSED_PARAM( p_driver_obj );\r
797 #endif\r
798 \r
799         CL_DEINIT;\r
800 \r
801         _free_child_device_list();\r
802 \r
803         RtlInitUnicodeString( &dos_name, \r
804                                 L"\\DosDevices\\Global\\VNICCONFIG" );\r
805         IoDeleteSymbolicLink( &dos_name );\r
806         \r
807 \r
808         IOU_EXIT( IOU_DBG_DRV );\r
809 }\r
810 \r
811 static \r
812 PDEVICE_OBJECT\r
813 initialize_ioctl_interface(\r
814         IN PDRIVER_OBJECT       p_driver_obj )\r
815 {\r
816         NTSTATUS        status;\r
817         UNICODE_STRING  dev_name, dos_name;\r
818         PDEVICE_OBJECT  p_dev_obj = NULL;\r
819 \r
820         RtlInitUnicodeString( &dev_name, L"\\Device\\VNICCONFIG" );\r
821         RtlInitUnicodeString( &dos_name, \r
822                         L"\\DosDevices\\Global\\VNICCONFIG" );\r
823 \r
824         status = IoCreateDevice( p_driver_obj, 0,\r
825                 &dev_name, FILE_DEVICE_UNKNOWN,\r
826                 FILE_DEVICE_SECURE_OPEN, FALSE, &p_dev_obj );\r
827 \r
828         if( !NT_SUCCESS( status ) )\r
829         {\r
830                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
831                         ( "Failed to create VNIC CONFIG device.\n" ) );\r
832                 return NULL;\r
833         }\r
834 \r
835         IoDeleteSymbolicLink( &dos_name );\r
836 \r
837         status = IoCreateSymbolicLink( &dos_name, &dev_name );\r
838         if(  !NT_SUCCESS( status ) )\r
839         {\r
840                 IoDeleteDevice( p_dev_obj );\r
841                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
842                         ( "Failed to create symlink for dos name.\n" ) );\r
843                 p_dev_obj = NULL;\r
844         }\r
845 \r
846         return p_dev_obj;\r
847 }\r
848 \r
849 NTSTATUS\r
850 DriverEntry(\r
851         IN                              DRIVER_OBJECT                           *p_driver_obj,\r
852         IN                              UNICODE_STRING                          *p_registry_path )\r
853 {\r
854         NTSTATUS                        status;\r
855 \r
856         IOU_ENTER( IOU_DBG_DRV );\r
857 \r
858 #if defined(EVENT_TRACING)\r
859         WPP_INIT_TRACING( p_driver_obj, p_registry_path );\r
860 #endif\r
861 \r
862         status = CL_INIT;\r
863         if( !NT_SUCCESS(status) )\r
864         {\r
865                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
866                         ("cl_init returned %08X.\n", status) );\r
867                 return status;\r
868         }\r
869 \r
870         /* Store the driver object pointer in the global parameters. */\r
871         iou_globals.p_driver_obj = p_driver_obj;\r
872         iou_globals.p_device_list = NULL;\r
873 \r
874         /* Get the registry values. */\r
875         status = __read_registry( p_registry_path );\r
876         if( !NT_SUCCESS(status) )\r
877         {\r
878                 CL_DEINIT;\r
879                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
880                         ("__read_registry returned %08x.\n", status) );\r
881                 return status;\r
882         }\r
883 \r
884         /* Setup the entry points. */\r
885         p_driver_obj->MajorFunction[IRP_MJ_CREATE] = iou_drv_open;\r
886         p_driver_obj->MajorFunction[IRP_MJ_CLEANUP] = iou_drv_cleanup;\r
887         p_driver_obj->MajorFunction[IRP_MJ_CLOSE] = iou_drv_close;\r
888 \r
889         p_driver_obj->MajorFunction[IRP_MJ_PNP] = cl_pnp;\r
890         p_driver_obj->MajorFunction[IRP_MJ_POWER] = cl_power;\r
891         p_driver_obj->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = iou_sysctl;\r
892         p_driver_obj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = iou_drv_ioctl;\r
893         p_driver_obj->DriverUnload = iou_unload;\r
894         p_driver_obj->DriverExtension->AddDevice = iou_add_device;\r
895 \r
896         iou_globals.p_config_device = initialize_ioctl_interface( p_driver_obj );\r
897 \r
898         cl_qlist_init( &iou_globals.ca_ioc_map_list );\r
899         cl_mutex_init( &iou_globals.list_mutex );\r
900 \r
901         IOU_EXIT( IOU_DBG_DRV );\r
902         return STATUS_SUCCESS;\r
903 }\r