[CORE] Expose vendor defined device in ibiou.
authorleonidk <leonidk@ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86>
Mon, 23 Mar 2009 18:49:29 +0000 (18:49 +0000)
committerleonidk <leonidk@ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86>
Mon, 23 Mar 2009 18:49:29 +0000 (18:49 +0000)
IBIOU driver doesn't create child PDO's on discovering a EVIC IOC.
It's behavior for SRP target IOCs is not altered and child devices for SRP targets will get created on their discovery.

IBIOU keeps a global list of reachable IOCs in iou_globals. IBIOU add/delete entries in this list on IOC ADD and IOC REMOVE PnP events.
User mode utility "qlgcvnic_config" is used to list all the reachable IOCs to the user and then to create the VNIC PDOs.
"qlgcvnic_config" uses device IOCTLs to communicate with the IBIOU driver.
IBIOU creates the devices only if sees that EVIC IOC is reachable from the particular CA.
"qlgcvnic_config" utility writes this device information into the registry also, so that IBIOU can pick up these device creation information on
next reboot.
In initialization phase, IBIOU reads the child device information from the registry and makes a list of VNIC child devices to be created.
On each IOC add events, it traverses the child device list (prepared during initialization) and create the child PDO for matching child device entries.

Signed off by: Deepak Gupta [deepak.gupta@qlogic.com]

git-svn-id: svn://openib.tc.cornell.edu/gen1/trunk@2039 ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86

core/al/al_dev.h
core/iou/kernel/SOURCES
core/iou/kernel/iou_driver.c
core/iou/kernel/iou_driver.h
core/iou/kernel/iou_ioc_mgr.c
core/iou/kernel/iou_ioc_mgr.h
core/iou/kernel/iou_pnp.c

index c67630f..212dada 100644 (file)
@@ -413,6 +413,15 @@ typedef enum _al_ndi_ops
 \r
 }      al_ndi_ops_t;\r
 \r
+typedef enum _al_ioc_device_config\r
+{\r
+       al_ioc_device_config_start = al_ndi_maxops,\r
+       ual_ioc_device_create,\r
+       ual_ioc_list,\r
+       al_ioc_device_config_maxops\r
+\r
+}      al_ioc_device_config_t;\r
+\r
 #define AL_NDI_OPS_START                       IOCTL_CODE(ALDEV_KEY, al_ndi_ops_start)\r
 #define AL_NDI_MAXOPS                          IOCTL_CODE(ALDEV_KEY, al_ndi_maxops)\r
 \r
@@ -547,4 +556,13 @@ typedef enum _al_ndi_ops
 #define UAL_DEREG_PNP          IOCTL_CODE(ALDEV_KEY, ual_dereg_pnp_cmd)\r
 #define UAL_ACCESS_FLASH       IOCTL_CODE(ALDEV_KEY, ual_access_flash)\r
 \r
+#define AL_IOC_DEVICE_CONFIG_START             IOCTL_CODE(ALDEV_KEY, al_ioc_device_config_start)\r
+#define AL_IOC_DEVICE_CONFIG_MAXOPS            IOCTL_CODE(ALDEV_KEY, al_ioc_device_config_maxops)\r
+\r
+#define IS_IOC_DEVICE_CONFIG_IOCTL(cmd)                \\r
+       ((cmd) > AL_IOC_DEVICE_CONFIG_START && (cmd) < AL_IOC_DEVICE_CONFIG_MAXOPS)\r
+\r
+#define UAL_IOC_DEVICE_CREATE                  IOCTL_CODE(ALDEV_KEY, ual_ioc_device_create)\r
+#define UAL_IOC_LIST                           IOCTL_CODE(ALDEV_KEY, ual_ioc_list)\r
+\r
 #endif /* _AL_DEV_H_ */\r
index 88befd1..1a628db 100644 (file)
@@ -22,7 +22,7 @@ SOURCES= ibiou.rc             \
        iou_pnp.c                       \\r
        iou_ioc_mgr.c\r
 \r
-INCLUDES=..\..\..\inc;..\..\..\inc\kernel;\r
+INCLUDES=..\..\..\inc;..\..\..\inc\kernel;..\..\..\core\al\r
 \r
 C_DEFINES=$(C_DEFINES) -DDRIVER -DDEPRECATE_DDK_FUNCTIONS -DNEED_CL_OBJ -DWPP_OLDCC\r
 \r
index fc6cc0b..60b1b55 100644 (file)
 #include "iou_driver.tmh"\r
 #endif\r
 #include "iou_pnp.h"\r
+#include "al_dev.h"\r
+#include "iou_ioc_mgr.h"\r
 #include <complib/cl_init.h>\r
-\r
+#include <complib/cl_bus_ifc.h>\r
 \r
 iou_globals_t  iou_globals = {\r
        NULL\r
@@ -67,6 +69,11 @@ iou_drv_close(
        IN                              DEVICE_OBJECT                           *p_dev_obj,\r
        IN                              IRP                                                     *p_irp );\r
 \r
+static NTSTATUS\r
+iou_drv_cleanup(\r
+       IN                              DEVICE_OBJECT                           *p_dev_obj,\r
+       IN                              IRP                                     *p_irp);\r
+\r
 static NTSTATUS\r
 iou_drv_ioctl(\r
        IN                              DEVICE_OBJECT                           *p_dev_obj,\r
@@ -85,6 +92,7 @@ static NTSTATUS
 iou_sysctl(\r
        IN                              DEVICE_OBJECT                           *p_dev_obj,\r
        IN                              IRP                                                     *p_irp );\r
+\r
 /**********/\r
 \r
 static void\r
@@ -97,6 +105,375 @@ DriverEntry(
        IN                              UNICODE_STRING                          *p_registry_path );\r
 \r
 \r
+static void    _free_child_device_list()\r
+{\r
+       child_device_info_list_t *pDevList, *pDevList1;\r
+\r
+       pDevList = iou_globals.p_device_list;\r
+\r
+       while( pDevList )\r
+       {\r
+               pDevList1 = pDevList->next_device_info;\r
+               cl_free( pDevList );\r
+               pDevList = pDevList1;\r
+       }\r
+\r
+}\r
+\r
+static NTSTATUS _build_child_device_list( PUNICODE_STRING p_param_path )\r
+{\r
+       RTL_QUERY_REGISTRY_TABLE        table[2];\r
+       UNICODE_STRING                  keyPath;\r
+       UNICODE_STRING                  keyValue;\r
+       UNICODE_STRING                  child_name;\r
+       WCHAR                           *key_path_buffer;\r
+       WCHAR                           *key_value_buffer;\r
+       WCHAR                           *static_child_name;\r
+       NTSTATUS                        status;\r
+       uint32_t                        instanceid = 1;\r
+       HANDLE                          hParamKey = NULL;\r
+       UNICODE_STRING                  valuename;\r
+       ULONG                           sizeofbuf;\r
+       PVOID                           pBuf = NULL;\r
+       PKEY_VALUE_FULL_INFORMATION     pKeyVal = NULL;\r
+       uint64_t                        guid_val = 0;\r
+       OBJECT_ATTRIBUTES               objattr;\r
+       WCHAR                           *curChild;\r
+       child_device_info_list_t        *pPrevList, *pNewDevList;\r
+\r
+       cl_memclr(  table, sizeof( table) );\r
+\r
+       /* use hard-coded size 256 to make it simple*/\r
+       key_path_buffer = cl_zalloc( 256*sizeof( WCHAR )*3 ) ;\r
+\r
+       if( !key_path_buffer )\r
+       {\r
+               IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR ,( "Not enough memeory for key_path_buffer.\n" ) );\r
+               status = STATUS_UNSUCCESSFUL;\r
+               goto _build_child_device_list_exit;\r
+       }\r
+\r
+       key_value_buffer = key_path_buffer + 256;\r
+       static_child_name = key_value_buffer + 256;\r
+\r
+       RtlInitUnicodeString( &keyPath, NULL );\r
+       keyPath.MaximumLength = 256*sizeof( WCHAR );\r
+       keyPath.Buffer = key_path_buffer;\r
+\r
+       RtlInitUnicodeString( &keyValue, NULL );\r
+       keyValue.MaximumLength = 256*sizeof( WCHAR );\r
+       keyValue.Buffer = key_value_buffer;\r
+\r
+       RtlInitUnicodeString( &child_name, NULL );\r
+       child_name.MaximumLength = 256*sizeof( WCHAR );\r
+       child_name.Buffer = static_child_name;\r
+\r
+\r
+       RtlCopyUnicodeString( &keyPath, p_param_path );\r
+\r
+       /* Setup the table entries. */\r
+       table[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND;\r
+       table[0].Name = L"StaticChild";\r
+       table[0].EntryContext = &child_name;\r
+       table[0].DefaultType = REG_NONE;\r
+\r
+       status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, \r
+               keyPath.Buffer, table, NULL, NULL );\r
+\r
+       if( !NT_SUCCESS( status ) )\r
+       {\r
+               if ( status == STATUS_INVALID_PARAMETER )\r
+               {\r
+                       IOU_PRINT(TRACE_LEVEL_WARNING, IOU_DBG_ERROR, \r
+                                       ("Failed to read registry values\n") );\r
+               }\r
+               goto _build_child_device_list_exit;\r
+       }\r
+\r
+       curChild = static_child_name;\r
+       pPrevList = iou_globals.p_device_list;\r
+       while( *curChild )\r
+       {\r
+               RtlCopyUnicodeString( &keyPath, p_param_path );\r
+               RtlAppendUnicodeToString( &keyPath, L"\\" );\r
+               RtlAppendUnicodeToString( &keyPath, curChild );\r
+\r
+               pNewDevList = cl_zalloc( sizeof( child_device_info_list_t ) );\r
+               if( !pNewDevList )\r
+               {\r
+                       IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR, \r
+                                       ( "Not enough memeory for key_path_buffer.\n" ) );\r
+                       status = STATUS_UNSUCCESSFUL;\r
+                       goto _build_child_device_list_exit;\r
+               }\r
+               pNewDevList->next_device_info = NULL;\r
+\r
+               if( pPrevList == NULL )\r
+               {\r
+                       iou_globals.p_device_list = pNewDevList;\r
+               }\r
+               else\r
+               {\r
+                       pPrevList->next_device_info = pNewDevList;\r
+               }\r
+\r
+               pPrevList = pNewDevList;\r
+\r
+               RtlInitUnicodeString( &keyValue, NULL );\r
+               keyValue.MaximumLength = sizeof( pNewDevList->io_device_info.device_id );\r
+               keyValue.Buffer = pNewDevList->io_device_info.device_id;\r
+\r
+               /* Setup the table entries. */\r
+               table[0].Flags = RTL_QUERY_REGISTRY_DIRECT;\r
+               table[0].Name = L"DeviceId";\r
+               table[0].EntryContext = &keyValue; \r
+               table[0].DefaultType = REG_NONE;\r
+\r
+               status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, \r
+                       keyPath.Buffer, table, NULL, NULL );\r
+               if( !NT_SUCCESS( status ) )\r
+               {\r
+                       IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR, \r
+                                       ( "Failed to read DeviceId.\n" ) );\r
+                       goto _build_child_device_list_exit;\r
+               }\r
+               pNewDevList->io_device_info.device_id_size = keyValue.Length + sizeof( WCHAR);\r
+\r
+               /* Get HardwareId*/\r
+               RtlInitUnicodeString( &keyValue, NULL );\r
+               keyValue.MaximumLength = sizeof( pNewDevList->io_device_info.hardware_id );\r
+               keyValue.Buffer = pNewDevList->io_device_info.hardware_id;\r
+\r
+               /* Setup the table entries. */\r
+               table[0].Flags = RTL_QUERY_REGISTRY_DIRECT;\r
+               table[0].Name = L"HardwareId";\r
+               table[0].EntryContext = &keyValue; \r
+               table[0].DefaultType = REG_NONE;\r
+\r
+               status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, \r
+                       keyPath.Buffer, table, NULL, NULL );\r
+               if( !NT_SUCCESS( status ) )\r
+               {\r
+                       IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR ,\r
+                                       ( "Failed to read HardwareId.\n" ) );\r
+                       goto _build_child_device_list_exit;\r
+               }\r
+               pNewDevList->io_device_info.hardware_id_size = keyValue.Length + 2*sizeof( WCHAR );\r
+               /* Get CompatibleId*/\r
+               RtlInitUnicodeString( &keyValue, NULL );\r
+               keyValue.MaximumLength = sizeof( pNewDevList->io_device_info.compatible_id );\r
+               keyValue.Buffer = pNewDevList->io_device_info.compatible_id;\r
+               /* Setup the table entries. */\r
+               table[0].Flags = RTL_QUERY_REGISTRY_DIRECT;\r
+               table[0].Name = L"CompatibleId";\r
+               table[0].EntryContext = &keyValue; \r
+               table[0].DefaultType = REG_NONE;\r
+\r
+               status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, \r
+                       keyPath.Buffer, table, NULL, NULL );\r
+               if( !NT_SUCCESS( status ) )\r
+               {\r
+                       IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR ,\r
+                                       ( "Failed to read CompatibleId.\n" ) );\r
+                       goto _build_child_device_list_exit;\r
+               }\r
+               pNewDevList->io_device_info.compatible_id_size = keyValue.Length + 2*sizeof( WCHAR ); //2 null\r
+\r
+               /* Get Description*/\r
+               RtlInitUnicodeString( &keyValue, NULL );\r
+               keyValue.MaximumLength = sizeof( pNewDevList->io_device_info.description );\r
+               keyValue.Buffer = pNewDevList->io_device_info.description;\r
+\r
+               /* Setup the table entries. */\r
+               table[0].Flags = RTL_QUERY_REGISTRY_DIRECT;\r
+               table[0].Name = L"Description";\r
+               table[0].EntryContext = &keyValue; \r
+               table[0].DefaultType = REG_NONE;\r
+\r
+               status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, \r
+                       keyPath.Buffer, table, NULL, NULL );\r
+               if( !NT_SUCCESS( status ) )\r
+               {\r
+                       IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR, \r
+                                       ( "Failed to read Description.\n" ) );\r
+                       goto _build_child_device_list_exit;\r
+               }\r
+\r
+               pNewDevList->io_device_info.description_size = keyValue.Length + sizeof( WCHAR );\r
+\r
+               if( ( pNewDevList->io_device_info.description_size > MAX_DEVICE_ID_LEN) ||\r
+                  ( pNewDevList->io_device_info.hardware_id_size > MAX_DEVICE_ID_LEN) ||\r
+                  ( pNewDevList->io_device_info.compatible_id_size > MAX_DEVICE_ID_LEN) ||\r
+                  ( pNewDevList->io_device_info.device_id_size > MAX_DEVICE_ID_LEN)\r
+                  )\r
+               {\r
+                       IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR, \r
+                                       ( "Id or description size is too big.\n" ) );\r
+                       status = STATUS_UNSUCCESSFUL;\r
+                       goto _build_child_device_list_exit;\r
+               }\r
+\r
+               InitializeObjectAttributes( &objattr, &keyPath, OBJ_KERNEL_HANDLE, NULL, NULL );\r
+\r
+               status = ZwOpenKey( &hParamKey, GENERIC_READ, &objattr );\r
+\r
+               if ( !NT_SUCCESS( status ) ) \r
+               {\r
+                       IOU_PRINT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR, \r
+                                       ( "ZwOpenKey failed with status %u\n",status ) );\r
+                       goto _build_child_device_list_exit;\r
+               }\r
+                       \r
+               RtlInitUnicodeString( &valuename, L"IOCGUID" );\r
+               status = ZwQueryValueKey( hParamKey, &valuename, KeyValueFullInformation, NULL, 0, &sizeofbuf );\r
+\r
+               if ( status == STATUS_BUFFER_OVERFLOW || status == STATUS_BUFFER_TOO_SMALL ) \r
+               {\r
+                       pBuf = cl_zalloc( sizeofbuf );\r
+               }\r
+\r
+               if ( !pBuf && !NT_SUCCESS( status ) ) \r
+               {\r
+                       IOU_PRINT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR, \r
+                                       ( "Either ZwQueryValueKey failed with status %u" \r
+                                         "or cl_zalloc failed\n",status ) );\r
+                       goto _build_child_device_list_exit;\r
+               }\r
+\r
+               status = ZwQueryValueKey( hParamKey, &valuename, KeyValueFullInformation, pBuf, sizeofbuf, &sizeofbuf );\r
+\r
+               if ( !NT_SUCCESS( status ) ) \r
+               {\r
+                       IOU_PRINT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR, \r
+                                       ( "ZwQueryValueKey failed with status %u\n",status ) );\r
+                       goto _build_child_device_list_exit;                             \r
+               }\r
+\r
+               pKeyVal = ( PKEY_VALUE_FULL_INFORMATION ) pBuf;\r
+\r
+               if ( pKeyVal->Type & REG_BINARY ) \r
+               {\r
+                       memcpy( &guid_val, ( ( ( char * ) pBuf ) + pKeyVal->DataOffset ), sizeof( uint64_t ) );\r
+                       pNewDevList->io_device_info.ca_ioc_path.info.profile.ioc_guid = guid_val;\r
+                       guid_val = 0;\r
+               } \r
+               else \r
+               {\r
+                       IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR, \r
+                                       ( "IOC GUID is not of REG_BINARY type\n" ) );\r
+                       goto _build_child_device_list_exit;                             \r
+               }\r
+               cl_free( pBuf );\r
+               pBuf = NULL;\r
+\r
+               RtlInitUnicodeString( &valuename, L"CAGUID" );\r
+               status = ZwQueryValueKey( hParamKey, &valuename, KeyValueFullInformation, NULL, 0, &sizeofbuf );\r
+\r
+               if ( status == STATUS_BUFFER_OVERFLOW || status == STATUS_BUFFER_TOO_SMALL ) \r
+               {\r
+                       pBuf = cl_zalloc( sizeofbuf );\r
+               }\r
+\r
+               if ( !pBuf && !NT_SUCCESS( status ) ) \r
+               {\r
+                       IOU_PRINT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR, \r
+                                       ( "Either ZwQueryValueKey failed with status %u"\r
+                                         "or cl_zalloc failed\n",status ) );\r
+                       goto _build_child_device_list_exit;                             \r
+               }\r
+\r
+               status = ZwQueryValueKey( hParamKey, &valuename, KeyValueFullInformation, pBuf, sizeofbuf, &sizeofbuf );\r
+\r
+               if ( !NT_SUCCESS( status ) ) \r
+               {\r
+                       IOU_PRINT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR, \r
+                                       ( "ZwQueryValueKey failed with status %u\n",status ) );\r
+                       goto _build_child_device_list_exit;                             \r
+               }\r
+\r
+               pKeyVal = ( PKEY_VALUE_FULL_INFORMATION ) pBuf;\r
+\r
+               if ( pKeyVal->Type & REG_BINARY ) \r
+               {\r
+                       memcpy( &guid_val, ( ( ( char * ) pBuf ) + pKeyVal->DataOffset ), sizeof( uint64_t ) );\r
+                       pNewDevList->io_device_info.ca_ioc_path.ca_guid = guid_val;     \r
+               } \r
+               else \r
+               {\r
+                       IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR, \r
+                                       ( "CA GUID is not of REG_BINARY type\n"));\r
+                       goto _build_child_device_list_exit;                             \r
+               }\r
+\r
+               cl_free( pBuf);\r
+               pBuf = NULL;\r
+\r
+               RtlInitUnicodeString( &valuename, L"InstanceId");\r
+               status = ZwQueryValueKey( hParamKey, &valuename, KeyValueFullInformation, NULL, 0, &sizeofbuf );\r
+\r
+               if ( status == STATUS_BUFFER_OVERFLOW || status == STATUS_BUFFER_TOO_SMALL ) \r
+               {\r
+               pBuf = cl_zalloc( sizeofbuf );\r
+               }\r
+\r
+               if ( !pBuf && !NT_SUCCESS( status ) ) \r
+               {\r
+                       IOU_PRINT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR, \r
+                                       ( "Either ZwQueryValueKey failed with status %u" \r
+                                         "or cl_zalloc failed\n",status ) );\r
+                       goto _build_child_device_list_exit;                             \r
+               }\r
+\r
+               status = ZwQueryValueKey( hParamKey, &valuename, KeyValueFullInformation, \r
+                               pBuf, sizeofbuf, &sizeofbuf );\r
+\r
+               if ( !NT_SUCCESS( status ) ) \r
+               {\r
+                       IOU_PRINT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR, \r
+                                       ( "ZwQueryValueKey failed with status %u\n",status ) );\r
+                       goto _build_child_device_list_exit;                             \r
+               }\r
+\r
+               pKeyVal = ( PKEY_VALUE_FULL_INFORMATION ) pBuf;\r
+\r
+               memcpy( &instanceid, ( ( ( char * ) pBuf ) + pKeyVal->DataOffset ), sizeof( instanceid ) );\r
+                       pNewDevList->io_device_info.uniqueinstanceid = instanceid;\r
+\r
+               cl_free( pBuf );\r
+               pBuf = NULL;\r
+                       \r
+               ZwClose( hParamKey );\r
+               hParamKey = NULL;\r
+\r
+               while( *curChild ) curChild++;\r
+               curChild++;\r
+\r
+       }\r
+\r
+\r
+_build_child_device_list_exit:\r
+       if( key_path_buffer )\r
+       {\r
+               cl_free( key_path_buffer );\r
+       }\r
+\r
+       if( !NT_SUCCESS( status ) )\r
+       {\r
+               _free_child_device_list();\r
+       }\r
+\r
+       if ( hParamKey != NULL ) \r
+       {\r
+               ZwClose( hParamKey );\r
+       }\r
+\r
+       if ( pBuf ) \r
+       {\r
+               cl_free( pBuf );\r
+       }\r
+\r
+       return status;\r
+}\r
 \r
 static NTSTATUS\r
 __read_registry(\r
@@ -152,6 +529,12 @@ __read_registry(
                g_iou_dbg_flags |= CL_DBG_ERROR;\r
 #endif\r
 \r
+       if(!NT_SUCCESS( _build_child_device_list (&param_path) ) ){\r
+       IOU_PRINT( TRACE_LEVEL_INFORMATION, IOU_DBG_DRV,\r
+                        ( "Failed to create devices\n" ) );\r
+       }\r
+\r
+\r
        IOU_PRINT( TRACE_LEVEL_INFORMATION, IOU_DBG_DRV,\r
                ("debug level %d debug flags 0x%.8x\n",\r
                g_iou_dbg_level,\r
@@ -162,6 +545,212 @@ __read_registry(
        return status;\r
 }\r
 \r
+static NTSTATUS\r
+_create_child_ioc_device(\r
+       IN                              child_device_info_t     *p_child_dev )\r
+{\r
+       child_device_info_list_t        *p_prev_list, *p_new_dev_list, *temp = NULL;\r
+       ca_ioc_map_t                    *p_ca_ioc_map;\r
+       ib_api_status_t                 ib_status;\r
+\r
+       p_prev_list = iou_globals.p_device_list;\r
+\r
+       p_ca_ioc_map = find_ca_ioc_map( p_child_dev->ca_ioc_path.ca_guid,\r
+                                       p_child_dev->ca_ioc_path.info.profile.ioc_guid );\r
+\r
+       if ( p_ca_ioc_map == NULL ) \r
+       {\r
+               return STATUS_INTERNAL_ERROR;\r
+       }\r
+\r
+       p_new_dev_list = cl_zalloc( sizeof( child_device_info_list_t ) );\r
+\r
+       if ( !p_new_dev_list ) \r
+       {\r
+               IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR,\r
+                             ( "Insufficient Memory\n" ) );\r
+               return STATUS_INSUFFICIENT_RESOURCES;\r
+       }\r
+\r
+       p_new_dev_list->io_device_info = *p_child_dev;\r
+       p_new_dev_list->next_device_info = NULL;\r
+\r
+       if( p_prev_list == NULL ) \r
+       {\r
+               iou_globals.p_device_list = p_new_dev_list;\r
+       } \r
+       else \r
+       {\r
+               temp = p_prev_list->next_device_info;\r
+               p_prev_list->next_device_info = p_new_dev_list;\r
+       }\r
+       p_new_dev_list->next_device_info = temp;\r
+       \r
+       ib_status = _create_ioc_pdo( &p_new_dev_list->io_device_info, p_ca_ioc_map );\r
+\r
+       if ( ib_status != IB_SUCCESS ) \r
+       {\r
+               IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR,\r
+                             ( "PDO creation for IOC failed\n" ) );\r
+               cl_free( p_new_dev_list );\r
+               return STATUS_INTERNAL_ERROR;\r
+       }\r
+\r
+       return STATUS_SUCCESS;\r
+} \r
+\r
+static ULONG\r
+_build_ca_ioc_list( ca_ioc_info_t      *p_info )\r
+{\r
+       cl_list_item_t  *p_item;\r
+       ca_ioc_map_t    *p_map;\r
+\r
+       p_item = cl_qlist_head( &iou_globals.ca_ioc_map_list );\r
+\r
+       while ( p_item != cl_qlist_end( &iou_globals.ca_ioc_map_list ) ) \r
+       {\r
+               p_map = ( ca_ioc_map_t  *) p_item;\r
+               p_info->ca_guid = p_map->ca_guid;\r
+               p_info->info = p_map->info;\r
+               cl_memcpy( p_info->svc_entry_array, p_map->svc_entry_array, \r
+                       sizeof( p_map->svc_entry_array ) );\r
+\r
+               p_item = cl_qlist_next( p_item );\r
+               p_info++;\r
+       }\r
+\r
+       return ( (ULONG) (sizeof(ca_ioc_info_t)*cl_qlist_count( &iou_globals.ca_ioc_map_list )) );\r
+}\r
+\r
+static NTSTATUS\r
+iou_drv_open(\r
+       IN                              DEVICE_OBJECT                           *p_dev_obj,\r
+       IN                              IRP                                                     *p_irp )\r
+{\r
+       IOU_ENTER( IOU_DBG_DRV );\r
+\r
+       UNUSED_PARAM( p_dev_obj );\r
+\r
+       CL_ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );\r
+\r
+       /* We always succeed file handles creation. */\r
+       p_irp->IoStatus.Status = STATUS_SUCCESS;\r
+       p_irp->IoStatus.Information = 0;\r
+       IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
+\r
+       IOU_EXIT( IOU_DBG_DRV );\r
+       return STATUS_SUCCESS;\r
+       \r
+}\r
+\r
+static NTSTATUS\r
+iou_drv_close(\r
+       IN                              DEVICE_OBJECT                           *p_dev_obj,\r
+       IN                              IRP                                                     *p_irp )\r
+{\r
+       UNUSED_PARAM( p_dev_obj );\r
+\r
+       p_irp->IoStatus.Status = STATUS_SUCCESS;\r
+       p_irp->IoStatus.Information = 0;\r
+       IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
+\r
+       return STATUS_SUCCESS;  \r
+}\r
+\r
+static NTSTATUS\r
+iou_drv_cleanup(\r
+       IN                              DEVICE_OBJECT                           *p_dev_obj,\r
+       IN                              IRP                                     *p_irp)\r
+{\r
+       IOU_ENTER( IOU_DBG_DRV );\r
+\r
+       UNUSED_PARAM( p_dev_obj );\r
+\r
+       CL_ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );\r
+\r
+       /*\r
+        * Note that we don't acquire the remove and stop lock on close to allow\r
+        * applications to close the device when the locks are already held.\r
+        */\r
+\r
+       /* Complete the IRP. */\r
+       p_irp->IoStatus.Status = STATUS_SUCCESS;\r
+       p_irp->IoStatus.Information = 0;\r
+       IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
+\r
+       IOU_EXIT( IOU_DBG_DRV );\r
+       return STATUS_SUCCESS;\r
+}\r
+\r
+static NTSTATUS\r
+iou_drv_ioctl(\r
+       IN                              DEVICE_OBJECT                           *p_dev_obj,\r
+       IN                              IRP                                                     *p_irp )\r
+{\r
+       NTSTATUS                status = STATUS_SUCCESS;\r
+       PIO_STACK_LOCATION      p_io_stack;\r
+       ULONG                   controlcode, n_bytes;\r
+       size_t                  n_iocs;\r
+       ca_ioc_info_t           *p_ca_ioc_info;\r
+       child_device_info_t     *p_child_dev;\r
+\r
+       IOU_ENTER( IOU_DBG_DRV );\r
+       CL_ASSERT( p_dev_obj );\r
+       CL_ASSERT( p_irp );\r
+       UNUSED_PARAM( p_dev_obj );\r
+\r
+       /* Get the stack location. */\r
+       p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
+       controlcode = p_io_stack->Parameters.DeviceIoControl.IoControlCode;\r
+       p_irp->IoStatus.Information = 0;\r
+\r
+       switch ( controlcode ) \r
+       {\r
+               case UAL_IOC_DEVICE_CREATE:\r
+                       p_child_dev = p_irp->AssociatedIrp.SystemBuffer;\r
+                       \r
+                       if ( sizeof( child_device_info_t) > \r
+                               ( p_io_stack->Parameters.DeviceIoControl.\r
+                                 InputBufferLength ) ) \r
+                       {\r
+                               status = STATUS_BUFFER_TOO_SMALL;\r
+                       } \r
+                       else \r
+                       {\r
+                               status = _create_child_ioc_device( p_child_dev );\r
+                       }\r
+                       break;\r
+\r
+               case UAL_IOC_LIST:\r
+                       p_ca_ioc_info = p_irp->AssociatedIrp.SystemBuffer;\r
+                       cl_mutex_acquire( &iou_globals.list_mutex );\r
+                       n_iocs = cl_qlist_count( &iou_globals.ca_ioc_map_list );\r
+\r
+                       if ( n_iocs*sizeof( ca_ioc_info_t) <= \r
+                               p_io_stack->Parameters.DeviceIoControl.\r
+                               OutputBufferLength )\r
+                       {\r
+                               n_bytes = _build_ca_ioc_list( p_ca_ioc_info );\r
+                               p_irp->IoStatus.Information = n_bytes;\r
+                               status = STATUS_SUCCESS;\r
+                       } \r
+                       else \r
+                       {\r
+                               status = STATUS_BUFFER_TOO_SMALL;\r
+                       }\r
+\r
+                       cl_mutex_release( &iou_globals.list_mutex );\r
+\r
+                       break;\r
+               default:\r
+                       status = STATUS_INVALID_DEVICE_REQUEST;\r
+                       break;\r
+       }\r
+\r
+       p_irp->IoStatus.Status = status;\r
+       IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
+       return status;\r
+}\r
 \r
 static NTSTATUS\r
 iou_sysctl(\r
@@ -193,11 +782,12 @@ iou_sysctl(
        return status;\r
 }\r
 \r
-\r
 static void\r
 iou_unload(\r
        IN                              DRIVER_OBJECT                           *p_driver_obj )\r
 {\r
+       UNICODE_STRING  dos_name;\r
+\r
        IOU_ENTER( IOU_DBG_DRV );\r
 \r
 #if defined(EVENT_TRACING)\r
@@ -208,9 +798,53 @@ iou_unload(
 \r
        CL_DEINIT;\r
 \r
+       _free_child_device_list();\r
+\r
+       RtlInitUnicodeString( &dos_name, \r
+                               L"\\DosDevices\\Global\\VNICCONFIG" );\r
+       IoDeleteSymbolicLink( &dos_name );\r
+       \r
+\r
        IOU_EXIT( IOU_DBG_DRV );\r
 }\r
 \r
+static \r
+PDEVICE_OBJECT\r
+initialize_ioctl_interface(\r
+       IN PDRIVER_OBJECT       p_driver_obj )\r
+{\r
+       NTSTATUS        status;\r
+       UNICODE_STRING  dev_name, dos_name;\r
+       PDEVICE_OBJECT  p_dev_obj = NULL;\r
+\r
+       RtlInitUnicodeString( &dev_name, L"\\Device\\VNICCONFIG" );\r
+       RtlInitUnicodeString( &dos_name, \r
+                       L"\\DosDevices\\Global\\VNICCONFIG" );\r
+\r
+       status = IoCreateDevice( p_driver_obj, 0,\r
+               &dev_name, FILE_DEVICE_UNKNOWN,\r
+               FILE_DEVICE_SECURE_OPEN, FALSE, &p_dev_obj );\r
+\r
+       if( !NT_SUCCESS( status ) )\r
+       {\r
+               IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
+                       ( "Failed to create VNIC CONFIG device.\n" ) );\r
+               return NULL;\r
+       }\r
+\r
+       IoDeleteSymbolicLink( &dos_name );\r
+\r
+       status = IoCreateSymbolicLink( &dos_name, &dev_name );\r
+       if(  !NT_SUCCESS( status ) )\r
+       {\r
+               IoDeleteDevice( p_dev_obj );\r
+               IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
+                       ( "Failed to create symlink for dos name.\n" ) );\r
+               p_dev_obj = NULL;\r
+       }\r
+\r
+       return p_dev_obj;\r
+}\r
 \r
 NTSTATUS\r
 DriverEntry(\r
@@ -235,6 +869,7 @@ DriverEntry(
 \r
        /* Store the driver object pointer in the global parameters. */\r
        iou_globals.p_driver_obj = p_driver_obj;\r
+       iou_globals.p_device_list = NULL;\r
 \r
        /* Get the registry values. */\r
        status = __read_registry( p_registry_path );\r
@@ -247,12 +882,22 @@ DriverEntry(
        }\r
 \r
        /* Setup the entry points. */\r
+       p_driver_obj->MajorFunction[IRP_MJ_CREATE] = iou_drv_open;\r
+       p_driver_obj->MajorFunction[IRP_MJ_CLEANUP] = iou_drv_cleanup;\r
+       p_driver_obj->MajorFunction[IRP_MJ_CLOSE] = iou_drv_close;\r
+\r
        p_driver_obj->MajorFunction[IRP_MJ_PNP] = cl_pnp;\r
        p_driver_obj->MajorFunction[IRP_MJ_POWER] = cl_power;\r
        p_driver_obj->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = iou_sysctl;\r
+       p_driver_obj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = iou_drv_ioctl;\r
        p_driver_obj->DriverUnload = iou_unload;\r
        p_driver_obj->DriverExtension->AddDevice = iou_add_device;\r
 \r
+       iou_globals.p_config_device = initialize_ioctl_interface( p_driver_obj );\r
+\r
+       cl_qlist_init( &iou_globals.ca_ioc_map_list );\r
+       cl_mutex_init( &iou_globals.list_mutex );\r
+\r
        IOU_EXIT( IOU_DBG_DRV );\r
        return STATUS_SUCCESS;\r
 }\r
index d082a84..b779cec 100644 (file)
@@ -190,7 +190,6 @@ typedef struct _iou_fdo_ext
 \r
 }      iou_fdo_ext_t;\r
 \r
-\r
 /*\r
  * Device extension for bus driver PDOs.\r
  */\r
@@ -238,7 +237,7 @@ typedef struct _iou_pdo_ext
         *      and thus not reported.\r
         */\r
        boolean_t                               b_reported_missing;\r
-\r
+       struct _child_device_info                       *p_pdo_device_info;\r
 }      iou_pdo_ext_t;\r
 \r
 \r
@@ -249,11 +248,16 @@ typedef struct _iou_globals
 {\r
        /* Driver object.  Used for creating child devices. */\r
        DRIVER_OBJECT                   *p_driver_obj;\r
-\r
+       struct _child_device_info_list *p_device_list;\r
+       cl_mutex_t                      list_mutex;\r
+       cl_qlist_t                      ca_ioc_map_list;\r
+       PDEVICE_OBJECT                  p_config_device;\r
 }      iou_globals_t;\r
 \r
 \r
 extern iou_globals_t   iou_globals;\r
 \r
 \r
+\r
+\r
 #endif /* !defined _IOU_DRIVER_H_ */\r
index 62e87f5..c475fdc 100644 (file)
@@ -249,7 +249,7 @@ ioc_mgr_construct(
        /* Construct the IOC manager service. */\r
        cl_obj_construct( &p_ioc_mgr->obj, 0 );\r
        cl_mutex_construct( &p_ioc_mgr->pdo_mutex );\r
-       cl_qlist_init( &p_ioc_mgr->ioc_list );\r
+       cl_qlist_init( &p_ioc_mgr->pdo_list );\r
 \r
        IOU_EXIT( IOU_DBG_PNP );\r
 }\r
@@ -274,6 +274,15 @@ ioc_mgr_init(
                return IB_ERROR;\r
        }\r
 \r
+       cl_status = cl_mutex_init( &p_ioc_mgr->pdo_mutex );\r
+       if( cl_status != CL_SUCCESS )\r
+       {\r
+               free_ioc_mgr( &p_ioc_mgr->obj );\r
+               IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
+                       ("cl_mutex_init returned %#x.\n", cl_status) );\r
+               return IB_ERROR;\r
+       }       \r
+\r
        /* Initialize the load service object. */\r
        cl_status = cl_obj_init( &p_ioc_mgr->obj, CL_DESTROY_SYNC,\r
                destroying_ioc_mgr, NULL, free_ioc_mgr );\r
@@ -367,13 +376,13 @@ free_ioc_mgr(
         * Mark all IOCs as no longer present.  This will cause them\r
         * to be removed when they process the IRP_MN_REMOVE_DEVICE.\r
         */\r
-       p_list_item = cl_qlist_remove_head( &p_ioc_mgr->ioc_list );\r
-       while( p_list_item != cl_qlist_end( &p_ioc_mgr->ioc_list ) )\r
+       p_list_item = cl_qlist_remove_head( &p_ioc_mgr->pdo_list );\r
+       while( p_list_item != cl_qlist_end( &p_ioc_mgr->pdo_list ) )\r
        {\r
                p_iou_ext = PARENT_STRUCT(\r
                        PARENT_STRUCT( p_list_item, iou_pdo_ext_t, list_item ),\r
                        ioc_ext_t, pdo );\r
-               p_list_item = cl_qlist_remove_head( &p_ioc_mgr->ioc_list );\r
+               p_list_item = cl_qlist_remove_head( &p_ioc_mgr->pdo_list );\r
                if( p_iou_ext->pdo.cl_ext.pnp_state == SurpriseRemoved )\r
                {\r
                        CL_ASSERT( !p_iou_ext->pdo.b_present );\r
@@ -438,7 +447,7 @@ ioc_mgr_get_iou_relations(
 \r
        /* If there are already relations, copy them. */\r
        cl_mutex_acquire( &p_ioc_mgr->pdo_mutex );\r
-       n_devs = cl_qlist_count( &p_ioc_mgr->ioc_list );\r
+       n_devs = cl_qlist_count( &p_ioc_mgr->pdo_list );        \r
        if( !n_devs )\r
        {\r
                cl_mutex_release( &p_ioc_mgr->pdo_mutex );\r
@@ -458,23 +467,40 @@ ioc_mgr_get_iou_relations(
        }\r
 \r
        p_rel = (DEVICE_RELATIONS*)p_irp->IoStatus.Information;\r
-       update_relations( &p_ioc_mgr->ioc_list, p_rel );\r
+       update_relations( &p_ioc_mgr->pdo_list, p_rel );\r
        cl_mutex_release( &p_ioc_mgr->pdo_mutex );\r
        IOU_EXIT( IOU_DBG_PNP );\r
        return STATUS_SUCCESS;\r
 }\r
 \r
+BOOLEAN is_vnic_profile_ioc(ib_ioc_profile_t   *p_profile)\r
+{\r
+       BOOLEAN b_vnic = FALSE;\r
+\r
+       if( ib_ioc_profile_get_vend_id( p_profile ) == 0x00066a &&\r
+               p_profile->dev_id == CL_HTON32(0x00000030) ) \r
+       {\r
+\r
+               b_vnic = TRUE;\r
+       }\r
+\r
+       return b_vnic;\r
+       \r
+}\r
 \r
 ib_api_status_t\r
 ioc_mgr_ioc_add(\r
        IN                              ib_pnp_ioc_rec_t*                       p_pnp_rec )\r
 {\r
        NTSTATUS                status;\r
-       DEVICE_OBJECT   *p_pdo;\r
+       DEVICE_OBJECT   *p_pdo = NULL;\r
        iou_fdo_ext_t   *p_ext;\r
        ioc_mgr_t               *p_ioc_mgr;\r
        ioc_ext_t               *p_ioc_ext;\r
        uint32_t                ext_size;\r
+       child_device_info_list_t *pCurList;\r
+       BOOLEAN                 b_vnic_ioc = FALSE;\r
+       ca_ioc_map_t            *p_map = NULL;\r
 \r
        IOU_ENTER( IOU_DBG_PNP );\r
 \r
@@ -491,9 +517,51 @@ ioc_mgr_ioc_add(
                return IB_NOT_DONE;\r
        }\r
 \r
+       p_map = cl_zalloc(sizeof(ca_ioc_map_t));\r
+\r
+       if ( !p_map ) \r
+       {\r
+               IOU_PRINT_EXIT(TRACE_LEVEL_INFORMATION, IOU_DBG_PNP, \r
+                               (" Insufficient Memory.\n" ));\r
+               return IB_INSUFFICIENT_MEMORY;\r
+       }\r
+\r
+       p_map->ca_guid = p_pnp_rec->ca_guid;\r
+       p_map->info = p_pnp_rec->info;\r
+       p_map->p_ioc_mgr = p_ioc_mgr;\r
+       cl_memcpy( p_map->svc_entry_array, p_pnp_rec->svc_entry_array,\r
+                       p_pnp_rec->info.profile.num_svc_entries );\r
+\r
+       cl_mutex_acquire(&iou_globals.list_mutex);\r
+       cl_qlist_insert_tail( &iou_globals.ca_ioc_map_list, &p_map->ioc_list);\r
+       cl_mutex_release( &iou_globals.list_mutex );\r
+\r
+       b_vnic_ioc = is_vnic_profile_ioc( &p_pnp_rec->info.profile );\r
+       pCurList = iou_globals.p_device_list;\r
+\r
+       if ( b_vnic_ioc && !pCurList ) \r
+       {\r
+               IOU_PRINT_EXIT(TRACE_LEVEL_INFORMATION, IOU_DBG_PNP, \r
+                               ("There is no device list for VNIC IOCs\n"));\r
+               return IB_NOT_DONE;\r
+       }\r
+\r
        ext_size = sizeof(ioc_ext_t) +\r
                (sizeof(ib_svc_entry_t) * p_pnp_rec->info.profile.num_svc_entries);\r
 \r
+       do\r
+       {\r
+               if ( b_vnic_ioc ) \r
+               {\r
+                       if ( p_pnp_rec->ca_guid != \r
+                               pCurList->io_device_info.ca_ioc_path.ca_guid ||\r
+                               p_pnp_rec->info.profile.ioc_guid != \r
+                               pCurList->io_device_info.ca_ioc_path.info.profile.ioc_guid)\r
+                       {\r
+                               pCurList = pCurList->next_device_info;\r
+                               continue;\r
+                       }\r
+               }\r
        /* Create the PDO for the new port device. */\r
        status = IoCreateDevice( iou_globals.p_driver_obj, ext_size,\r
                NULL, FILE_DEVICE_CONTROLLER,\r
@@ -520,6 +588,13 @@ ioc_mgr_ioc_add(
        p_ioc_ext->pdo.b_reported_missing = FALSE;\r
        p_ioc_ext->pdo.ca_guid = p_pnp_rec->ca_guid;\r
                \r
+\r
+               if ( b_vnic_ioc ) \r
+               {\r
+                       p_ioc_ext->pdo.p_pdo_device_info = &pCurList->io_device_info;\r
+               }\r
+\r
+               \r
        /* Copy the IOC profile and service entries. */\r
        p_ioc_ext->info = p_pnp_rec->info;\r
        cl_memcpy( p_ioc_ext->svc_entries, p_pnp_rec->svc_entry_array,\r
@@ -529,50 +604,118 @@ ioc_mgr_ioc_add(
 \r
        /* Store the device extension in the PDO list for future queries. */\r
        cl_mutex_acquire( &p_ioc_mgr->pdo_mutex );\r
-       cl_qlist_insert_tail( &p_ioc_mgr->ioc_list,\r
+               cl_qlist_insert_tail( &p_ioc_mgr->pdo_list,\r
                &p_ioc_ext->pdo.list_item );\r
        cl_mutex_release( &p_ioc_mgr->pdo_mutex );\r
 \r
+               IoInvalidateDeviceRelations( p_ext->cl_ext.p_pdo, BusRelations );\r
+\r
+               if ( b_vnic_ioc ) \r
+               {\r
+                       pCurList = pCurList->next_device_info;\r
+               } \r
+               else \r
+               {\r
+                       break;\r
+               }\r
+\r
+\r
+       } while( pCurList );\r
+\r
        /*\r
         * Set the context of the PNP event.  The context is passed in for future\r
         * events on the same port.\r
         */\r
-       p_pnp_rec->pnp_rec.context = p_ioc_ext;\r
 \r
+       //p_pnp_rec->pnp_rec.context = p_ioc_ext;\r
        /* Tell the PnP Manager to rescan for bus relations. */\r
-       IoInvalidateDeviceRelations( p_ext->cl_ext.p_pdo, BusRelations );\r
 \r
        IOU_EXIT( IOU_DBG_PNP );\r
        return IB_SUCCESS;\r
 }\r
 \r
 \r
+ca_ioc_map_t   *find_ca_ioc_map(net64_t        ca_guid,\r
+                                ib_net64_t     ioc_guid/*ib_pnp_ioc_rec_t      *p_pnp_rec*/)\r
+{\r
+       cl_list_item_t  *list_item;\r
+       ca_ioc_map_t    *p_map = NULL;\r
+\r
+       cl_mutex_acquire( &iou_globals.list_mutex );\r
+\r
+       list_item = cl_qlist_head( &iou_globals.ca_ioc_map_list );\r
+\r
+       while( list_item != cl_qlist_end( &iou_globals.ca_ioc_map_list ) ) \r
+       {\r
+               p_map = ( ca_ioc_map_t * ) list_item;\r
+               if ( p_map->ca_guid != ca_guid || \r
+                   p_map->info.profile.ioc_guid != ioc_guid )\r
+               {\r
+\r
+                       list_item = cl_qlist_next( list_item );\r
+                       continue;\r
+               }\r
+               break;\r
+       }\r
+\r
+       if ( list_item == cl_qlist_end( &iou_globals.ca_ioc_map_list ) )\r
+               p_map = NULL;\r
+\r
+       cl_mutex_release( &iou_globals.list_mutex );\r
+       return p_map;\r
+}\r
+\r
 void\r
 ioc_mgr_ioc_remove(\r
        IN                              ib_pnp_ioc_rec_t*                       p_pnp_rec )\r
 {\r
        ioc_mgr_t       *p_ioc_mgr;\r
        ioc_ext_t       *p_ioc_ext;\r
+       iou_pdo_ext_t   *p_iou_pdo_ext;\r
+\r
+       ca_ioc_map_t    *p_map;\r
+       cl_list_item_t  *list_item;\r
 \r
        IOU_ENTER( IOU_DBG_PNP );\r
 \r
-       /* The PNP record's context is the IOC's device extension. */\r
-       p_ioc_ext = p_pnp_rec->pnp_rec.context;\r
-       CL_ASSERT( p_ioc_ext );\r
+       p_ioc_mgr = PARENT_STRUCT( p_pnp_rec->pnp_rec.pnp_context, ioc_mgr_t, obj );\r
+\r
+       p_map = find_ca_ioc_map( p_pnp_rec->ca_guid, \r
+                               p_pnp_rec->info.profile.ioc_guid );\r
 \r
-       p_ioc_mgr = &p_ioc_ext->pdo.p_parent_ext->ioc_mgr;\r
-       /*\r
-        * Flag the port IOC as no longer being present.  We have to wait until\r
-        * the PnP manager removes it to clean up.\r
-        */\r
+       if ( p_map ) \r
+       {\r
+               cl_mutex_acquire( &iou_globals.list_mutex );\r
+               cl_qlist_remove_item( &iou_globals.ca_ioc_map_list, &p_map->ioc_list );\r
+               cl_mutex_release( &iou_globals.list_mutex );\r
+               cl_free(p_map);\r
+       } \r
+\r
+       list_item = cl_qlist_head(&p_ioc_mgr->pdo_list); \r
+\r
+       while ( list_item != cl_qlist_end(&p_ioc_mgr->pdo_list) )\r
+       {\r
+               p_iou_pdo_ext = PARENT_STRUCT(list_item, iou_pdo_ext_t, list_item);\r
+               p_ioc_ext = PARENT_STRUCT(p_iou_pdo_ext, ioc_ext_t, pdo);\r
+\r
+               if ( p_pnp_rec->ca_guid != p_ioc_ext->pdo.ca_guid ||\r
+                   p_pnp_rec->info.profile.ioc_guid != \r
+                   p_ioc_ext->info.profile.ioc_guid ) \r
+               {\r
+                       list_item = cl_qlist_next( list_item );\r
+                       continue;\r
+               }\r
        cl_mutex_acquire( &p_ioc_mgr->pdo_mutex );\r
        p_ioc_ext->pdo.b_present = FALSE;\r
+               cl_mutex_release( &p_ioc_mgr->pdo_mutex );\r
 \r
+               list_item = cl_qlist_next( list_item );\r
        /* Invalidate bus relations for the bus root. */\r
        IoInvalidateDeviceRelations(\r
                p_ioc_ext->pdo.p_parent_ext->cl_ext.p_pdo, BusRelations );\r
 \r
-       cl_mutex_release( &p_ioc_mgr->pdo_mutex );\r
+\r
+       }\r
 \r
        IOU_EXIT( IOU_DBG_PNP );\r
 }\r
@@ -618,7 +761,7 @@ ioc_release_resources(
        cl_mutex_acquire( &p_ioc_mgr->pdo_mutex );\r
        IOU_PRINT( TRACE_LEVEL_INFORMATION, IOU_DBG_PNP,\r
                ("Removing IOC from list.\n") );\r
-       cl_qlist_remove_item( &p_ioc_mgr->ioc_list, &p_ext->pdo.list_item );\r
+       cl_qlist_remove_item( &p_ioc_mgr->pdo_list, &p_ext->pdo.list_item );\r
        cl_mutex_release( &p_ioc_mgr->pdo_mutex );\r
        po_state.DeviceState = PowerDeviceD3;\r
        PoSetPowerState( p_ext->pdo.cl_ext.p_pdo, DevicePowerState, po_state );\r
@@ -789,13 +932,15 @@ ioc_query_device_id(
        IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
                OUT                             IRP* const                              p_irp )\r
 {\r
-       NTSTATUS                        status;\r
        ioc_ext_t                       *p_ext;\r
        WCHAR                           *p_string;\r
+       uint32_t                        dev_id_size;\r
+       NTSTATUS                        status;\r
 \r
        IOU_ENTER( IOU_DBG_PNP );\r
 \r
        p_ext = (ioc_ext_t*)p_dev_obj->DeviceExtension;\r
+\r
        if( !p_ext->pdo.b_present )\r
        {\r
                IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
@@ -803,6 +948,26 @@ ioc_query_device_id(
                return STATUS_NO_SUCH_DEVICE;\r
        }\r
 \r
+       if (p_ext->pdo.p_pdo_device_info) \r
+       {\r
+\r
+               dev_id_size = (p_ext->pdo.p_pdo_device_info)->device_id_size;\r
+               p_string = ExAllocatePoolWithTag( PagedPool, dev_id_size, 'didq' );\r
+\r
+               if( !p_string )\r
+               {\r
+                       IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
+                               ( "Failed to allocate device ID buffer (%u bytes).\n",\r
+                               dev_id_size ) );\r
+                       return STATUS_INSUFFICIENT_RESOURCES;\r
+               }\r
+\r
+               RtlZeroMemory( p_string, dev_id_size );\r
+\r
+               cl_memcpy( p_string, p_ext->pdo.p_pdo_device_info->device_id, dev_id_size );\r
+       } \r
+       else \r
+       {\r
        p_string = ExAllocatePoolWithTag( PagedPool, IOC_DEV_ID_SIZE, 'didq' );\r
        if( !p_string )\r
        {\r
@@ -826,6 +991,9 @@ ioc_query_device_id(
                        ("Failed to format device ID string.\n") );\r
                return status;\r
        }\r
+               \r
+       }\r
+\r
        p_irp->IoStatus.Information = (ULONG_PTR)p_string;\r
 \r
        IOU_EXIT( IOU_DBG_PNP );\r
@@ -838,12 +1006,12 @@ ioc_query_hardware_ids(
        IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
                OUT                             IRP* const                              p_irp )\r
 {\r
-       NTSTATUS                        status;\r
        ioc_ext_t                       *p_ext;\r
        WCHAR                           *p_string, *p_start;\r
        size_t                          size;\r
-       uint32_t                        V,P,S,s;\r
+       uint32_t                        V,P,S,s, hw_id_size;\r
        uint16_t                        v;\r
+       NTSTATUS                        status;\r
 \r
        IOU_ENTER( IOU_DBG_PNP );\r
 \r
@@ -855,6 +1023,25 @@ ioc_query_hardware_ids(
                return STATUS_NO_SUCH_DEVICE;\r
        }\r
 \r
+       if (p_ext->pdo.p_pdo_device_info) \r
+       {\r
+               hw_id_size = p_ext->pdo.p_pdo_device_info->hardware_id_size;\r
+\r
+               p_string = ExAllocatePoolWithTag( PagedPool, hw_id_size, 'ihqi' );\r
+               if( !p_string )\r
+               {\r
+                       IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
+                               ( "Failed to allocate hardware ID buffer (%d bytes).\n",\r
+                               hw_id_size ) );\r
+                       return STATUS_INSUFFICIENT_RESOURCES;\r
+               }\r
+\r
+               RtlZeroMemory( p_string, hw_id_size );\r
+\r
+               cl_memcpy( p_string, p_ext->pdo.p_pdo_device_info->hardware_id, hw_id_size );\r
+       } \r
+       else \r
+       {\r
        p_string = ExAllocatePoolWithTag( PagedPool, IOC_HW_ID_SIZE, 'ihqi' );\r
        if( !p_string )\r
        {\r
@@ -919,6 +1106,8 @@ ioc_query_hardware_ids(
                        ("Failed to format hardware ID string.\n") );\r
                return status;\r
        }\r
+       }\r
+\r
        p_irp->IoStatus.Information = (ULONG_PTR)p_string;\r
 \r
        IOU_EXIT( IOU_DBG_PNP );\r
@@ -931,11 +1120,13 @@ ioc_query_compatible_ids(
        IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
                OUT                             IRP* const                              p_irp )\r
 {\r
-       NTSTATUS                        status;\r
        ioc_ext_t                       *p_ext;\r
        WCHAR                           *p_string, *p_start;\r
+       uint32_t                        compat_id_size;\r
        size_t                          size;\r
        uint16_t                        C, c, p, r;\r
+       NTSTATUS                        status;\r
+\r
 \r
        IOU_ENTER( IOU_DBG_PNP );\r
 \r
@@ -947,6 +1138,27 @@ ioc_query_compatible_ids(
                return STATUS_NO_SUCH_DEVICE;\r
        }\r
 \r
+       if ( p_ext->pdo.p_pdo_device_info )\r
+       {\r
+\r
+               compat_id_size = p_ext->pdo.p_pdo_device_info->compatible_id_size;\r
+\r
+               p_string = ExAllocatePoolWithTag( PagedPool, compat_id_size, 'icqi' );\r
+\r
+               if( !p_string )\r
+               {\r
+                       IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
+                               ("Failed to allocate compatible ID buffer (%d bytes).\n",\r
+                               compat_id_size) );\r
+                       return STATUS_INSUFFICIENT_RESOURCES;\r
+               }\r
+\r
+               RtlZeroMemory( p_string, compat_id_size );\r
+\r
+               cl_memcpy( p_string, p_ext->pdo.p_pdo_device_info->compatible_id, compat_id_size );\r
+       } \r
+       else \r
+       {\r
        p_string = ExAllocatePoolWithTag( PagedPool, IOC_COMPAT_ID_SIZE, 'icqi' );\r
        if( !p_string )\r
        {\r
@@ -985,6 +1197,8 @@ ioc_query_compatible_ids(
                        ("Failed to format device ID string.\n") );\r
                return status;\r
        }\r
+       }\r
+\r
        p_irp->IoStatus.Information = (ULONG_PTR)p_string;\r
 \r
        IOU_EXIT( IOU_DBG_PNP );\r
@@ -1012,6 +1226,32 @@ ioc_query_unique_id(
        }\r
 \r
        /* The instance ID is the port GUID. */\r
+       if ( p_ext->pdo.p_pdo_device_info ) \r
+       {\r
+\r
+               p_string = ExAllocatePoolWithTag( PagedPool, sizeof(WCHAR) * 41, 'iuqi' );\r
+               if( !p_string )\r
+               {\r
+                       IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
+                               ("Failed to allocate instance ID buffer (%d bytes).\n",\r
+                               sizeof(WCHAR) * 41) );\r
+                       return STATUS_NO_MEMORY;\r
+               }\r
+\r
+               status = RtlStringCchPrintfW ( p_string, 41, L"%016I64x%016I64x%08x",\r
+                                        p_ext->info.profile.ioc_guid, p_ext->pdo.ca_guid,\r
+                                        p_ext->pdo.p_pdo_device_info->uniqueinstanceid);\r
+               if( !NT_SUCCESS( status ) )\r
+               {\r
+                       CL_ASSERT( NT_SUCCESS( status ) );\r
+                       ExFreePool( p_string );\r
+                       IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
+                               ("RtlStringCchPrintfW returned %08x.\n", status) );\r
+                       return status;\r
+               }\r
+       } \r
+       else \r
+       {\r
        p_string = ExAllocatePoolWithTag( PagedPool, sizeof(WCHAR) * 33, 'iuqi' );\r
        if( !p_string )\r
        {\r
@@ -1032,6 +1272,8 @@ ioc_query_unique_id(
                return status;\r
        }\r
 \r
+       }\r
+\r
        p_irp->IoStatus.Information = (ULONG_PTR)p_string;\r
 \r
        IOU_EXIT( IOU_DBG_PNP );\r
@@ -1058,6 +1300,26 @@ ioc_query_description(
                return STATUS_NO_SUCH_DEVICE;\r
        }\r
 \r
+       if ( p_ext->pdo.p_pdo_device_info ) \r
+       {\r
+               p_string = ExAllocatePoolWithTag( PagedPool, p_ext->pdo.p_pdo_device_info->description_size, \r
+                                               'edqi' );\r
+               if( !p_string )\r
+               {\r
+                       IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
+                               ( "Failed to allocate description buffer (%d bytes).\n",\r
+                               p_ext->pdo.p_pdo_device_info->description_size ) );\r
+                       return STATUS_INSUFFICIENT_RESOURCES;\r
+               }\r
+\r
+               RtlZeroMemory( p_string, p_ext->pdo.p_pdo_device_info->description_size );\r
+\r
+               cl_memcpy( p_string, p_ext->pdo.p_pdo_device_info->description,\r
+                               p_ext->pdo.p_pdo_device_info->description_size );\r
+\r
+       } \r
+       else \r
+       {\r
        p_string = ExAllocatePoolWithTag( PagedPool,\r
                                                                          sizeof(WCHAR) * sizeof(p_ext->info.profile.id_string),\r
                                                                          'edqi');\r
@@ -1097,6 +1359,8 @@ ioc_query_description(
                        ("RtlStringCchPrintfW returned %08x.\n", status) );\r
                return status;\r
        }\r
+       }\r
+\r
        p_irp->IoStatus.Information = (ULONG_PTR)p_string;\r
 \r
        IOU_EXIT( IOU_DBG_PNP );\r
@@ -1369,3 +1633,84 @@ ioc_set_power(
        IOU_EXIT( IOU_DBG_POWER );\r
        return STATUS_SUCCESS;\r
 }\r
+\r
+ib_api_status_t\r
+_create_ioc_pdo(\r
+       IN                              child_device_info_t*                    p_child_dev,\r
+       IN                              ca_ioc_map_t*                           p_ca_ioc_map)\r
+{\r
+       NTSTATUS                status;\r
+       DEVICE_OBJECT   *p_pdo = NULL;\r
+       iou_fdo_ext_t   *p_ext;\r
+       ioc_mgr_t               *p_ioc_mgr;\r
+       ioc_ext_t               *p_ioc_ext;\r
+       uint32_t                ext_size;\r
+       BOOLEAN                 b_vnic_ioc = FALSE;\r
+\r
+       p_ioc_mgr = p_ca_ioc_map->p_ioc_mgr;\r
+\r
+       p_ext = PARENT_STRUCT( p_ioc_mgr, iou_fdo_ext_t, ioc_mgr );\r
+\r
+       if( p_child_dev->ca_ioc_path.ca_guid != p_ioc_mgr->info.ca_guid ||\r
+               p_child_dev->ca_ioc_path.info.chassis_guid != p_ioc_mgr->info.chassis_guid ||\r
+               p_child_dev->ca_ioc_path.info.chassis_slot != p_ioc_mgr->info.slot||\r
+               p_child_dev->ca_ioc_path.info.iou_guid != p_ioc_mgr->info.guid )\r
+       {\r
+               IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_PNP,\r
+                       ("Child PDO's IOC not in this IOU.\n") );\r
+               return IB_NOT_DONE;\r
+       }\r
+\r
+       ext_size = sizeof(ioc_ext_t) +\r
+               ( sizeof(ib_svc_entry_t) * p_ca_ioc_map->info.profile.num_svc_entries );\r
+\r
+       status = IoCreateDevice( iou_globals.p_driver_obj, ext_size,\r
+                       NULL, FILE_DEVICE_CONTROLLER,\r
+                       FILE_DEVICE_SECURE_OPEN | FILE_AUTOGENERATED_DEVICE_NAME,\r
+                       FALSE, &p_pdo );\r
+       if( !NT_SUCCESS( status ) )\r
+       {\r
+               IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
+                       ( "IoCreateDevice returned %08x.\n", status ) );\r
+               return IB_ERROR;\r
+       }\r
+\r
+       b_vnic_ioc = is_vnic_profile_ioc( &p_ca_ioc_map->info.profile );        \r
+\r
+       /* Initialize the device extension. */\r
+       cl_init_pnp_po_ext( p_pdo, NULL, p_pdo, g_iou_dbg_flags,\r
+               &vfptr_ioc_pnp, &vfptr_iou_query_txt );\r
+       /* Set the DO_BUS_ENUMERATED_DEVICE flag to mark it as a PDO. */\r
+       p_pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;\r
+\r
+       p_ioc_ext = p_pdo->DeviceExtension;\r
+       p_ioc_ext->pdo.dev_po_state.DeviceState = PowerDeviceD0;\r
+       p_ioc_ext->pdo.p_parent_ext = p_ext;\r
+       p_ioc_ext->pdo.b_present = TRUE;\r
+       p_ioc_ext->pdo.b_reported_missing = FALSE;\r
+       p_ioc_ext->pdo.ca_guid = p_child_dev->ca_ioc_path.ca_guid;\r
+\r
+       if ( b_vnic_ioc ) \r
+       {\r
+               p_ioc_ext->pdo.p_pdo_device_info = p_child_dev;\r
+       }\r
+\r
+       /* Copy the IOC profile and service entries. */\r
+       p_ioc_ext->info = p_child_dev->ca_ioc_path.info;\r
+       cl_memcpy( p_ioc_ext->svc_entries, p_child_dev->ca_ioc_path.svc_entry_array,\r
+               p_child_dev->ca_ioc_path.info.profile.num_svc_entries );\r
+       /* Make sure the IOC string is null terminated. */\r
+       p_ioc_ext->info.profile.id_string[CTRL_ID_STRING_LEN-1] = '\0';\r
+\r
+       /* Store the device extension in the PDO list for future queries. */\r
+       cl_mutex_acquire( &p_ioc_mgr->pdo_mutex );\r
+       cl_qlist_insert_tail( &p_ioc_mgr->pdo_list,\r
+                               &p_ioc_ext->pdo.list_item );\r
+       cl_mutex_release( &p_ioc_mgr->pdo_mutex );\r
+\r
+       IoInvalidateDeviceRelations( p_ext->cl_ext.p_pdo, BusRelations );\r
+\r
+       IOU_EXIT(IOU_DBG_PNP);\r
+\r
+       return IB_SUCCESS;\r
+}\r
index 19c2f6f..330b241 100644 (file)
@@ -57,11 +57,59 @@ typedef struct _ioc_mgr
        cl_mutex_t                                      pdo_mutex;\r
 \r
        /* Pointer vector of child IOC PDOs. */\r
-       cl_qlist_t                                      ioc_list;\r
+       cl_qlist_t                                      pdo_list;\r
 \r
 }      ioc_mgr_t;\r
 \r
 \r
+#pragma pack(push, 1)\r
+\r
+/* Windows pnp device information */\r
+#define MAX_DEVICE_ID_LEN     200\r
+#define MAX_DEVICE_STRING_LEN          MAX_DEVICE_ID_LEN + 2   //add extra 4 bytes in case we need double NULL ending\r
+\r
+typedef struct _ca_ioc_info {\r
+       net64_t                                 ca_guid;\r
+       ib_ioc_info_t                           info;\r
+       ib_svc_entry_t                          svc_entry_array[1];\r
+} ca_ioc_info_t;\r
+\r
+typedef struct _child_device_info {\r
+       wchar_t         device_id[MAX_DEVICE_STRING_LEN];  \r
+       uint32_t        device_id_size;\r
+       wchar_t         compatible_id[MAX_DEVICE_STRING_LEN];\r
+       uint32_t        compatible_id_size;\r
+       wchar_t         hardware_id[MAX_DEVICE_STRING_LEN];\r
+       uint32_t        hardware_id_size;\r
+       wchar_t         description[MAX_DEVICE_STRING_LEN];\r
+       uint32_t        description_size;\r
+       ca_ioc_info_t   ca_ioc_path;\r
+       uint32_t        uniqueinstanceid;\r
+}  child_device_info_t;\r
+\r
+typedef struct _child_device_info_list{\r
+       struct _child_device_info_list *next_device_info;\r
+       child_device_info_t io_device_info;\r
+}child_device_info_list_t;\r
+\r
+typedef struct _ca_ioc_map {\r
+       cl_list_item_t                          ioc_list;\r
+       ioc_mgr_t                               *p_ioc_mgr;\r
+       net64_t                                 ca_guid;\r
+       ib_ioc_info_t                           info;\r
+       ib_svc_entry_t                          svc_entry_array[1];\r
+} ca_ioc_map_t;\r
+#pragma pack(pop)\r
+\r
+ib_api_status_t\r
+_create_ioc_pdo(\r
+       IN                              child_device_info_t*                    p_child_dev,\r
+       IN                              ca_ioc_map_t*                           p_ca_ioc_map);\r
+\r
+ca_ioc_map_t   *find_ca_ioc_map(net64_t        ca_guid,\r
+                                ib_net64_t     ioc_guid);\r
+\r
+\r
 void\r
 ioc_mgr_construct(\r
        IN      OUT                     ioc_mgr_t* const                        p_ioc_mgr );\r
index 617ffd8..002412e 100644 (file)
@@ -138,7 +138,6 @@ static const cl_vfptr_pnp_po_t              vfptr_fdo_pnp = {
  * our interface so that user-mode AL can find a device to perform IOCTLs to.\r
  */\r
 \r
-\r
 NTSTATUS\r
 iou_add_device(\r
        IN                              DRIVER_OBJECT                           *p_driver_obj,\r
@@ -289,6 +288,29 @@ fdo_query_remove(
        return STATUS_SUCCESS;\r
 }\r
 \r
+static void _destroy_ca_ioc_maps(\r
+       IN                                      ioc_mgr_t       *p_ioc_mgr)\r
+{\r
+       ca_ioc_map_t    *p_map = NULL;\r
+       cl_list_item_t  *list_item;\r
+\r
+       cl_mutex_acquire( &iou_globals.list_mutex );\r
+\r
+       list_item = cl_qlist_head( &iou_globals.ca_ioc_map_list );\r
+\r
+       while( list_item != cl_qlist_end( &iou_globals.ca_ioc_map_list ) ) {\r
+               p_map = ( ca_ioc_map_t  * ) list_item;\r
+               list_item = cl_qlist_next( list_item ); // Get the next element before freeing it\r
+\r
+               if ( p_map->p_ioc_mgr == p_ioc_mgr ) {\r
+                       cl_qlist_remove_item( &iou_globals.ca_ioc_map_list, ( cl_list_item_t * )p_map );\r
+                       cl_free( p_map );\r
+               }\r
+\r
+       }\r
+\r
+       cl_mutex_release( &iou_globals.list_mutex );\r
+}\r
 \r
 /*\r
  * This function gets called after releasing the remove lock and waiting\r
@@ -305,6 +327,8 @@ fdo_release_resources(
 \r
        p_ext = p_dev_obj->DeviceExtension;\r
 \r
+       _destroy_ca_ioc_maps(&p_ext->ioc_mgr);\r
+\r
        //TODO: Fail outstanding I/O operations.\r
        cl_obj_destroy( &p_ext->ioc_mgr.obj );\r
 \r
@@ -609,3 +633,5 @@ update_relations(
 \r
        IOU_EXIT( IOU_DBG_PNP );\r
 }\r
+\r
+\r