/*++ Copyright (C) Microsoft Corporation, 1996 - 1999 Module Name: map.c Abstract: This module contains routines for maintaining the SCSI device map in the registry. Authors: Peter Wieland Environment: Kernel mode only Notes: Revision History: --*/ #include "port.h" #define __FILE_ID__ 'map ' HANDLE ScsiDeviceMapKey = (HANDLE) -1; VOID SpDeleteLogicalUnitDeviceMapEntry( PLOGICAL_UNIT_EXTENSION LogicalUnit ); VOID SpDeleteAdapterDeviceMap( PADAPTER_EXTENSION Adapter ); NTSTATUS SpBuildAdapterDeviceMap( IN PADAPTER_EXTENSION Adapter ); NTSTATUS SpBuildLogicalUnitDeviceMapEntry( IN PLOGICAL_UNIT_EXTENSION LogicalUnit ); NTSTATUS SpCreateNumericKey( IN HANDLE Root, IN ULONG Name, IN PWSTR Prefix, IN BOOLEAN Create, OUT PHANDLE NewKey, OUT PULONG Disposition ); #ifdef ALLOC_PRAGMA #pragma alloc_text(INIT, SpInitDeviceMap) #pragma alloc_text(PAGE, SpBuildDeviceMapEntry) #pragma alloc_text(PAGE, SpBuildAdapterDeviceMap) #pragma alloc_text(PAGE, SpBuildLogicalUnitDeviceMapEntry) #pragma alloc_text(PAGE, SpDeleteLogicalUnitDeviceMapEntry) #pragma alloc_text(PAGE, SpDeleteAdapterDeviceMap) #pragma alloc_text(PAGE, SpUpdateLogicalUnitDeviceMapEntry) #pragma alloc_text(PAGE, SpCreateNumericKey) #endif NTSTATUS SpInitDeviceMap( VOID ) /*++ Routine Description: Arguments: Return Value: status --*/ { UNICODE_STRING name; OBJECT_ATTRIBUTES objectAttributes; HANDLE mapKey; ULONG disposition; ULONG i; NTSTATUS status; PAGED_CODE(); // // Open the SCSI key in the device map. // RtlInitUnicodeString(&name, L"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi"); InitializeObjectAttributes(&objectAttributes, &name, OBJ_CASE_INSENSITIVE, NULL, (PSECURITY_DESCRIPTOR) NULL); // // Create or open the key. // status = ZwCreateKey(&mapKey, KEY_READ | KEY_WRITE, &objectAttributes, 0, (PUNICODE_STRING) NULL, REG_OPTION_VOLATILE, &disposition); if(NT_SUCCESS(status)) { ScsiDeviceMapKey = mapKey; } else { ScsiDeviceMapKey = NULL; } return status; } NTSTATUS SpBuildDeviceMapEntry( IN PCOMMON_EXTENSION CommonExtension ) /*++ Routine Description: This routine will make an entry for the specified adapter or logical unit in the SCSI device map in the registry. This table is maintained for debugging and legacy use. A handle to the device map key for this device will be stored in the common device extension. This handle should only be used within the context of a system thread. Arguments: Extension - the object we are adding to the device map. Return Value: status --*/ { PAGED_CODE(); if(CommonExtension->IsPdo) { return SpBuildLogicalUnitDeviceMapEntry((PLOGICAL_UNIT_EXTENSION) CommonExtension); } else { return SpBuildAdapterDeviceMap((PADAPTER_EXTENSION) CommonExtension); } } NTSTATUS SpBuildLogicalUnitDeviceMapEntry( IN PLOGICAL_UNIT_EXTENSION LogicalUnit ) { PADAPTER_EXTENSION adapter = LogicalUnit->AdapterExtension; HANDLE busKey; PCWSTR typeString; ANSI_STRING ansiString; UNICODE_STRING name; UNICODE_STRING unicodeString; ULONG disposition; NTSTATUS status; PAGED_CODE(); ASSERT(LogicalUnit->IsTemporary == FALSE); DebugPrint((1, "SpBuildDeviceMapEntry: Building map entry for lun %p\n", LogicalUnit)); if(adapter->BusDeviceMapKeys == NULL) { // // We don't have keys built for the buses yet. Bail out. // return STATUS_UNSUCCESSFUL; } // // If we already have a target or LUN key for this device then we're done. // if((LogicalUnit->TargetDeviceMapKey != NULL) && (LogicalUnit->LunDeviceMapKey != NULL)) { return STATUS_SUCCESS; } busKey = adapter->BusDeviceMapKeys[LogicalUnit->PathId].BusKey; // // Create a key for the target // status = SpCreateNumericKey(busKey, LogicalUnit->TargetId, L"Target Id ", TRUE, &(LogicalUnit->TargetDeviceMapKey), &disposition); if(!NT_SUCCESS(status)) { return status; } // // Create the LUN entry // status = SpCreateNumericKey(LogicalUnit->TargetDeviceMapKey, LogicalUnit->Lun, L"Logical Unit Id ", TRUE, &(LogicalUnit->LunDeviceMapKey), &disposition); if(!NT_SUCCESS(status)) { return status; } // // Create the identifier value // RtlInitUnicodeString(&name, L"Identifier"); // // Get the identifier from the inquiry data // ansiString.MaximumLength = 28; ansiString.Length = 28; ansiString.Buffer = LogicalUnit->InquiryData.VendorId; status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE); if(NT_SUCCESS(status)) { status = ZwSetValueKey(LogicalUnit->LunDeviceMapKey, &name, 0, REG_SZ, unicodeString.Buffer, unicodeString.Length + sizeof(WCHAR)); RtlFreeUnicodeString(&unicodeString); } // // Determine the peripheral type // typeString = SpGetDeviceTypeInfo(LogicalUnit->InquiryData.DeviceType)->DeviceMapString; // // Set type value. // RtlInitUnicodeString(&name, L"Type"); status = ZwSetValueKey(LogicalUnit->LunDeviceMapKey, &name, 0, REG_SZ, (PVOID) typeString, (wcslen(typeString) + 1) * sizeof(WCHAR)); // // Write the inquiry data into the device map for debugging purposes // RtlInitUnicodeString(&name, L"InquiryData"); status = ZwSetValueKey(LogicalUnit->LunDeviceMapKey, &name, 0, REG_BINARY, &(LogicalUnit->InquiryData), INQUIRYDATABUFFERSIZE); // // Convert the serial number into unicode and write it out to the // registry. // // // Get the identifier from the inquiry data // if(LogicalUnit->SerialNumber.Length != 0) { RtlInitUnicodeString(&name, L"SerialNumber"); status = RtlAnsiStringToUnicodeString( &unicodeString, &(LogicalUnit->SerialNumber), TRUE); if(NT_SUCCESS(status)) { status = ZwSetValueKey(LogicalUnit->LunDeviceMapKey, &name, 0, REG_SZ, unicodeString.Buffer, unicodeString.Length + sizeof(WCHAR)); RtlFreeUnicodeString(&unicodeString); } } // // If the device identifier page exists then write it out to the registry // if(LogicalUnit->DeviceIdentifierPage != NULL) { RtlInitUnicodeString(&name, L"DeviceIdentifierPage"); status = ZwSetValueKey(LogicalUnit->LunDeviceMapKey, &name, 0, REG_BINARY, LogicalUnit->DeviceIdentifierPage, LogicalUnit->DeviceIdentifierPageLength); } return STATUS_SUCCESS; } NTSTATUS SpBuildAdapterDeviceMap( IN PADAPTER_EXTENSION Adapter ) { PSCSIPORT_DRIVER_EXTENSION driverExtension; HANDLE mapKey; UNICODE_STRING name; OBJECT_ATTRIBUTES objectAttributes; ULONG disposition; ULONG i; NTSTATUS status; PUNICODE_STRING servicePath; ULONG busNumber; PAGED_CODE(); // // Grab the handle to the SCSI device map out of the driver extension. // driverExtension = IoGetDriverObjectExtension( Adapter->DeviceObject->DriverObject, ScsiPortInitialize); ASSERT(driverExtension != NULL); mapKey = ScsiDeviceMapKey; if(mapKey == NULL) { // // For some reason we were unable to create the root of the device map // during scsiport initialization. // return STATUS_UNSUCCESSFUL; } // // Create a key beneath this for the port device // status = SpCreateNumericKey(mapKey, Adapter->PortNumber, L"Scsi Port ", TRUE, &(Adapter->PortDeviceMapKey), &disposition); if(!NT_SUCCESS(status)) { return status; } // // Indicate if it's a PCCARD // if(RtlEqualMemory(&GUID_BUS_TYPE_PCMCIA, &(Adapter->BusTypeGuid), sizeof(GUID))) { RtlInitUnicodeString(&name, L"PCCARD"); i = 1; status = ZwSetValueKey(Adapter->PortDeviceMapKey, &name, 0, REG_DWORD, &i, sizeof(ULONG)); } // // Set the interrupt value // if(Adapter->InterruptLevel) { RtlInitUnicodeString(&name, L"Interrupt"); i = Adapter->InterruptLevel; status = ZwSetValueKey(Adapter->PortDeviceMapKey, &name, 0, REG_DWORD, &i, sizeof(ULONG)); } // // Set the base I/O address value // if(Adapter->IoAddress) { RtlInitUnicodeString(&name, L"IOAddress"); i = Adapter->IoAddress; status = ZwSetValueKey(Adapter->PortDeviceMapKey, &name, 0, REG_DWORD, &i, sizeof(ULONG)); } if(Adapter->Dma64BitAddresses) { RtlInitUnicodeString(&name, L"Dma64BitAddresses"); i = 0x1; status = ZwSetValueKey(Adapter->PortDeviceMapKey, &name, 0, REG_DWORD, &i, sizeof(ULONG)); } servicePath = &driverExtension->RegistryPath; ASSERT(servicePath != NULL); // // Add identifier value. This value is equal to the name of the driver // in the service key. Note the service key name is not NULL terminated // { PWSTR start; WCHAR buffer[32]; RtlInitUnicodeString(&name, L"Driver"); // // Get the name of the driver from the service key name. // start = (PWSTR) ((PCHAR) servicePath->Buffer + servicePath->Length); start--; while(*start != L'\\' && start > servicePath->Buffer) { start--; } if(*start == L'\\') { start++; for(i = 0; i < 31; i++) { buffer[i] = *start++; if(start >= (servicePath->Buffer + (servicePath->Length / sizeof(WCHAR)))) { break; } } i++; buffer[i] = L'\0'; status = ZwSetValueKey(Adapter->PortDeviceMapKey, &name, 0, REG_SZ, buffer, (i + 1) * sizeof(WCHAR)); } } // // Allocate storage for all the bus handles. // Adapter->BusDeviceMapKeys = SpAllocatePool( PagedPool, (sizeof(DEVICE_MAP_HANDLES) * Adapter->NumberOfBuses), SCSIPORT_TAG_DEVICE_MAP, Adapter->DeviceObject->DriverObject); if(Adapter->BusDeviceMapKeys == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } RtlZeroMemory(Adapter->BusDeviceMapKeys, (sizeof(DEVICE_MAP_HANDLES) * Adapter->NumberOfBuses)); // // Create a key for each bus. In each bus key create an empty key // the initiator. // for(busNumber = 0; busNumber < Adapter->NumberOfBuses; busNumber++) { PDEVICE_MAP_HANDLES busKeys; HANDLE busKey; HANDLE targetKey; busKeys = &(Adapter->BusDeviceMapKeys[busNumber]); // // Create a key entry for the bus. // status = SpCreateNumericKey( Adapter->PortDeviceMapKey, busNumber, L"Scsi Bus ", TRUE, &(busKeys->BusKey), &disposition); if(!NT_SUCCESS(status)) { continue; } // // Now create a key for the initiator. // i = Adapter->PortConfig->InitiatorBusId[busNumber]; status = SpCreateNumericKey(busKeys->BusKey, i, L"Initiator Id ", TRUE, &(busKeys->InitiatorKey), &disposition); if(!NT_SUCCESS(status)) { continue; } } return STATUS_SUCCESS; } VOID SpDeleteDeviceMapEntry( IN PCOMMON_EXTENSION CommonExtension ) { if(CommonExtension->IsPdo) { SpDeleteLogicalUnitDeviceMapEntry((PLOGICAL_UNIT_EXTENSION) CommonExtension); } else { SpDeleteAdapterDeviceMap((PADAPTER_EXTENSION) CommonExtension); } return; } VOID SpDeleteLogicalUnitDeviceMapEntry( PLOGICAL_UNIT_EXTENSION LogicalUnit ) { if(LogicalUnit->LunDeviceMapKey != NULL) { ASSERT(LogicalUnit->IsTemporary == FALSE); ZwDeleteKey(LogicalUnit->LunDeviceMapKey); ZwClose(LogicalUnit->LunDeviceMapKey); LogicalUnit->LunDeviceMapKey = NULL; } if(LogicalUnit->TargetDeviceMapKey != NULL) { ASSERT(LogicalUnit->IsTemporary == FALSE); ZwDeleteKey(LogicalUnit->TargetDeviceMapKey); ZwClose(LogicalUnit->TargetDeviceMapKey); LogicalUnit->TargetDeviceMapKey = NULL; } return; } VOID SpDeleteAdapterDeviceMap( PADAPTER_EXTENSION Adapter ) { if(Adapter->BusDeviceMapKeys != NULL) { ULONG busNumber; // // for each bus on the adapter. // for(busNumber = 0; busNumber < Adapter->NumberOfBuses; busNumber++) { PDEVICE_MAP_HANDLES busKeys; busKeys = &(Adapter->BusDeviceMapKeys[busNumber]); // // Attempt to delete the key for the initiator if it was created. // if(busKeys->InitiatorKey != NULL) { ZwDeleteKey(busKeys->InitiatorKey); ZwClose(busKeys->InitiatorKey); } // // Attempt to delete the key for the bus if it was created. // if(busKeys->BusKey != NULL) { ZwDeleteKey(busKeys->BusKey); ZwClose(busKeys->BusKey); } } ExFreePool(Adapter->BusDeviceMapKeys); Adapter->BusDeviceMapKeys = NULL; } // // Attempt to delete the key for the adapter if it was created. // if(Adapter->PortDeviceMapKey != NULL) { ZwDeleteKey(Adapter->PortDeviceMapKey); ZwClose(Adapter->PortDeviceMapKey); Adapter->PortDeviceMapKey = NULL; } return; } NTSTATUS SpCreateNumericKey( IN HANDLE Root, IN ULONG Name, IN PWSTR Prefix, IN BOOLEAN Create, OUT PHANDLE NewKey, OUT PULONG Disposition ) /*++ Routine Description: This function creates a registry key. The name of the key is a string version of numeric value passed in. Arguments: RootKey - Supplies a handle to the key where the new key should be inserted. Name - Supplies the numeric value to name the key. Prefix - Supplies a prefix name to add to name. Create - if TRUE the key will be created if it does not already exist. NewKey - Returns the handle for the new key. Disposition - the disposition value set by ZwCreateKey. Return Value: Returns the status of the operation. --*/ { UNICODE_STRING string; UNICODE_STRING stringNum; OBJECT_ATTRIBUTES objectAttributes; WCHAR bufferNum[16]; WCHAR buffer[64]; NTSTATUS status; PAGED_CODE(); // // Copy the Prefix into a string. // string.Length = 0; string.MaximumLength=64; string.Buffer = buffer; RtlInitUnicodeString(&stringNum, Prefix); RtlCopyUnicodeString(&string, &stringNum); // // Create a port number key entry. // stringNum.Length = 0; stringNum.MaximumLength = 16; stringNum.Buffer = bufferNum; status = RtlIntegerToUnicodeString(Name, 10, &stringNum); if (!NT_SUCCESS(status)) { return status; } // // Append the prefix and the numeric name. // RtlAppendUnicodeStringToString(&string, &stringNum); InitializeObjectAttributes( &objectAttributes, &string, OBJ_CASE_INSENSITIVE, Root, (PSECURITY_DESCRIPTOR) NULL ); if(Create) { status = ZwCreateKey(NewKey, KEY_READ | KEY_WRITE, &objectAttributes, 0, (PUNICODE_STRING) NULL, REG_OPTION_VOLATILE, Disposition ); } else { status = ZwOpenKey(NewKey, KEY_READ | KEY_WRITE, &objectAttributes); *Disposition = REG_OPENED_EXISTING_KEY; } return(status); } NTSTATUS SpUpdateLogicalUnitDeviceMapEntry( IN PLOGICAL_UNIT_EXTENSION LogicalUnit ) { UNICODE_STRING name; PAGED_CODE(); if((LogicalUnit->TargetDeviceMapKey == NULL) || (LogicalUnit->LunDeviceMapKey == NULL)) { return STATUS_UNSUCCESSFUL; } // // Write the inquiry data into the device map for debugging purposes // RtlInitUnicodeString(&name, L"InquiryData"); ZwSetValueKey(LogicalUnit->LunDeviceMapKey, &name, 0, REG_BINARY, &(LogicalUnit->InquiryData), INQUIRYDATABUFFERSIZE); return STATUS_SUCCESS; }