update for HEAD-2003021201
[reactos.git] / drivers / storage / scsiport / scsiport.c
index 8269d0f..3592b24 100644 (file)
 
 /* TYPES *********************************************************************/
 
-
+/*
+ * SCSI_PORT_TIMER_STATES
+ *
+ * DESCRIPTION
+ *     An enumeration containing the states in the timer DFA
+ */
 typedef enum _SCSI_PORT_TIMER_STATES
 {
   IDETimerIdle,
@@ -51,6 +56,17 @@ typedef enum _SCSI_PORT_TIMER_STATES
 } SCSI_PORT_TIMER_STATES;
 
 
+typedef struct _SCSI_PORT_DEVICE_BASE
+{
+  LIST_ENTRY List;
+
+  PVOID MappedAddress;
+  ULONG NumberOfBytes;
+  SCSI_PHYSICAL_ADDRESS IoAddress;
+  ULONG SystemIoBusNumber;
+} SCSI_PORT_DEVICE_BASE, *PSCSI_PORT_DEVICE_BASE;
+
+
 /*
  * SCSI_PORT_DEVICE_EXTENSION
  *
@@ -65,46 +81,39 @@ typedef struct _SCSI_PORT_DEVICE_EXTENSION
   ULONG MiniPortExtensionSize;
   PORT_CONFIGURATION_INFORMATION PortConfig;
   ULONG PortNumber;
-  
+
   KSPIN_LOCK IrpLock;
   KSPIN_LOCK SpinLock;
   PKINTERRUPT Interrupt;
   PIRP                   CurrentIrp;
   ULONG IrpFlags;
-  
+
   SCSI_PORT_TIMER_STATES TimerState;
   LONG                   TimerCount;
-  
+
   BOOLEAN Initializing;
-  
+
+  LIST_ENTRY DeviceBaseListHead;
+
   ULONG PortBusInfoSize;
   PSCSI_ADAPTER_BUS_INFO PortBusInfo;
-  
+
   PIO_SCSI_CAPABILITIES PortCapabilities;
-  
+
   PDEVICE_OBJECT DeviceObject;
   PCONTROLLER_OBJECT ControllerObject;
-  
+
   PHW_STARTIO HwStartIo;
   PHW_INTERRUPT HwInterrupt;
-  
+
   PSCSI_REQUEST_BLOCK OriginalSrb;
   SCSI_REQUEST_BLOCK InternalSrb;
   SENSE_DATA InternalSenseData;
-  
+
   UCHAR MiniPortDeviceExtension[1]; /* must be the last entry */
 } SCSI_PORT_DEVICE_EXTENSION, *PSCSI_PORT_DEVICE_EXTENSION;
 
 
-/*
- * SCSI_PORT_TIMER_STATES
- *
- * DESCRIPTION
- *     An enumeration containing the states in the timer DFA
- */
-
-
-
 #define IRP_FLAG_COMPLETE      0x00000001
 #define IRP_FLAG_NEXT          0x00000002
 
@@ -139,7 +148,8 @@ ScsiPortStartPacket(IN OUT PVOID Context);
 static NTSTATUS
 ScsiPortCreatePortDevice(IN PDRIVER_OBJECT DriverObject,
                         IN PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension,
-                        IN ULONG PortCount);
+                        IN ULONG PortCount,
+                        IN OUT PSCSI_PORT_DEVICE_EXTENSION *RealDeviceExtension);
 
 static VOID
 ScsiPortInquire(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
@@ -162,6 +172,11 @@ static PSCSI_REQUEST_BLOCK
 ScsiPortInitSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
                            PSCSI_REQUEST_BLOCK OriginalSrb);
 
+static NTSTATUS
+ScsiPortBuildDeviceMap(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+                      PUNICODE_STRING RegistryPath);
+
+
 /* FUNCTIONS *****************************************************************/
 
 /**********************************************************************
@@ -246,6 +261,7 @@ ScsiPortCompleteRequest(IN PVOID HwDeviceExtension,
                        IN UCHAR Lun,
                        IN UCHAR SrbStatus)
 {
+  DPRINT("ScsiPortCompleteRequest()\n");
   UNIMPLEMENTED;
 }
 
@@ -253,6 +269,7 @@ ScsiPortCompleteRequest(IN PVOID HwDeviceExtension,
 ULONG STDCALL
 ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address)
 {
+  DPRINT("ScsiPortConvertPhysicalAddressToUlong()\n");
   return(Address.u.LowPart);
 }
 
@@ -260,6 +277,7 @@ ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address)
 VOID STDCALL
 ScsiPortFlushDma(IN PVOID HwDeviceExtension)
 {
+  DPRINT("ScsiPortFlushDma()\n");
   UNIMPLEMENTED;
 }
 
@@ -268,7 +286,36 @@ VOID STDCALL
 ScsiPortFreeDeviceBase(IN PVOID HwDeviceExtension,
                       IN PVOID MappedAddress)
 {
-  UNIMPLEMENTED;
+  PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+  PSCSI_PORT_DEVICE_BASE DeviceBase;
+  PLIST_ENTRY Entry;
+
+  DPRINT("ScsiPortFreeDeviceBase() called\n");
+
+  DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
+                                     SCSI_PORT_DEVICE_EXTENSION,
+                                     MiniPortDeviceExtension);
+  if (IsListEmpty(&DeviceExtension->DeviceBaseListHead))
+    return;
+
+  Entry = DeviceExtension->DeviceBaseListHead.Flink;
+  while (Entry != &DeviceExtension->DeviceBaseListHead)
+    {
+      DeviceBase = CONTAINING_RECORD(Entry,
+                                    SCSI_PORT_DEVICE_BASE,
+                                    List);
+      if (DeviceBase->MappedAddress == MappedAddress)
+       {
+         MmUnmapIoSpace(DeviceBase->MappedAddress,
+                        DeviceBase->NumberOfBytes);
+         RemoveEntryList(Entry);
+         ExFreePool(DeviceBase);
+
+         return;
+       }
+
+      Entry = Entry->Flink;
+    }
 }
 
 
@@ -296,34 +343,48 @@ ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension,
                      IN ULONG NumberOfBytes,
                      IN BOOLEAN InIoSpace)
 {
-  ULONG AddressSpace;
+  PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
   PHYSICAL_ADDRESS TranslatedAddress;
-  PVOID VirtualAddress;
-  PVOID Buffer;
-  BOOLEAN rc;
+  PSCSI_PORT_DEVICE_BASE DeviceBase;
+  ULONG AddressSpace;
+  PVOID MappedAddress;
 
-  AddressSpace = (ULONG)InIoSpace;
+  DPRINT("ScsiPortGetDeviceBase() called\n");
 
-  if (!HalTranslateBusAddress(BusType,
-                             SystemIoBusNumber,
-                             IoAddress,
-                             &AddressSpace,
-                             &TranslatedAddress))
+  AddressSpace = (ULONG)InIoSpace;
+  if (HalTranslateBusAddress(BusType,
+                            SystemIoBusNumber,
+                            IoAddress,
+                            &AddressSpace,
+                            &TranslatedAddress) == FALSE)
     return NULL;
 
   /* i/o space */
   if (AddressSpace != 0)
-    return (PVOID)TranslatedAddress.u.LowPart;
+    return((PVOID)TranslatedAddress.u.LowPart);
+
+  MappedAddress = MmMapIoSpace(TranslatedAddress,
+                              NumberOfBytes,
+                              FALSE);
+
+  DeviceBase = ExAllocatePool(NonPagedPool,
+                             sizeof(SCSI_PORT_DEVICE_BASE));
+  if (DeviceBase == NULL)
+    return(MappedAddress);
 
-  VirtualAddress = MmMapIoSpace(TranslatedAddress,
-                               NumberOfBytes,
-                               FALSE);
+  DeviceBase->MappedAddress = MappedAddress;
+  DeviceBase->NumberOfBytes = NumberOfBytes;
+  DeviceBase->IoAddress = IoAddress;
+  DeviceBase->SystemIoBusNumber = SystemIoBusNumber;
 
-  Buffer = ExAllocatePool(NonPagedPool,0x20);
-  if (Buffer == NULL)
-    return VirtualAddress;
+  DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
+                                     SCSI_PORT_DEVICE_EXTENSION,
+                                     MiniPortDeviceExtension);
 
-  return NULL;  /* ?? */
+  InsertHeadList(&DeviceExtension->DeviceBaseListHead,
+                &DeviceBase->List);
+
+  return(MappedAddress);
 }
 
 
@@ -333,6 +394,7 @@ ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension,
                       IN UCHAR TargetId,
                       IN UCHAR Lun)
 {
+  DPRINT("ScsiPortGetLogicalUnit()\n");
   UNIMPLEMENTED;
 }
 
@@ -343,6 +405,7 @@ ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension,
                           IN PVOID VirtualAddress,
                           OUT ULONG *Length)
 {
+  DPRINT("ScsiPortGetPhysicalAddress()\n");
   UNIMPLEMENTED;
 }
 
@@ -354,6 +417,7 @@ ScsiPortGetSrb(IN PVOID DeviceExtension,
               IN UCHAR Lun,
               IN LONG QueueTag)
 {
+  DPRINT("ScsiPortGetSrb()\n");
   UNIMPLEMENTED;
 }
 
@@ -363,6 +427,7 @@ ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension,
                             IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
                             IN ULONG NumberOfBytes)
 {
+  DPRINT("ScsiPortGetUncachedExtension()\n");
   UNIMPLEMENTED;
 }
 
@@ -371,6 +436,7 @@ PVOID STDCALL
 ScsiPortGetVirtualAddress(IN PVOID HwDeviceExtension,
                          IN SCSI_PHYSICAL_ADDRESS PhysicalAddress)
 {
+  DPRINT("ScsiPortGetVirtualAddress()\n");
   UNIMPLEMENTED;
 }
 
@@ -411,6 +477,7 @@ ScsiPortInitialize(IN PVOID Argument1,
   PDRIVER_OBJECT DriverObject = (PDRIVER_OBJECT)Argument1;
   PUNICODE_STRING RegistryPath = (PUNICODE_STRING)Argument2;
   PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension;
+  PSCSI_PORT_DEVICE_EXTENSION RealDeviceExtension;
   PCONFIGURATION_INFORMATION SystemConfig;
   PPORT_CONFIGURATION_INFORMATION PortConfig;
   BOOLEAN Again;
@@ -464,6 +531,8 @@ ScsiPortInitialize(IN PVOID Argument1,
     ExAllocatePool(PagedPool,
                   sizeof(ACCESS_RANGE) * PortConfig->NumberOfAccessRanges);
 
+  for (i = 0; i < SCSI_MAXIMUM_BUSES; i++)
+    PortConfig->InitiatorBusId[i] = 255;
 
   PortConfig->SystemIoBusNumber = 0;
   PortConfig->SlotNumber = 0;
@@ -476,6 +545,8 @@ ScsiPortInitialize(IN PVOID Argument1,
     {
       DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig->SystemIoBusNumber);
 
+      InitializeListHead(&PseudoDeviceExtension->DeviceBaseListHead);
+
 //      RtlZeroMemory(AccessRanges,
 //                 sizeof(ACCESS_RANGE) * PortConfig->NumberOfAccessRanges);
 
@@ -497,7 +568,8 @@ ScsiPortInitialize(IN PVOID Argument1,
 
          Status = ScsiPortCreatePortDevice(DriverObject,
                                            PseudoDeviceExtension,
-                                           SystemConfig->ScsiPortCount);
+                                           SystemConfig->ScsiPortCount,
+                                           &RealDeviceExtension);
 
          if (!NT_SUCCESS(Status))
            {
@@ -509,6 +581,10 @@ ScsiPortInitialize(IN PVOID Argument1,
              return(Status);
            }
 
+         /* Build the registry device map */
+         ScsiPortBuildDeviceMap(RealDeviceExtension,
+                                (PUNICODE_STRING)Argument2);
+
          /* Update the configuration info */
          SystemConfig->AtDiskPrimaryAddressClaimed = PortConfig->AtdiskPrimaryClaimed;
          SystemConfig->AtDiskSecondaryAddressClaimed = PortConfig->AtdiskSecondaryClaimed;
@@ -544,6 +620,7 @@ ScsiPortIoMapTransfer(IN PVOID HwDeviceExtension,
                      IN ULONG LogicalAddress,
                      IN ULONG Length)
 {
+  DPRINT("ScsiPortIoMapTransfer()\n");
   UNIMPLEMENTED;
 }
 
@@ -557,6 +634,7 @@ ScsiPortLogError(IN PVOID HwDeviceExtension,
                 IN ULONG ErrorCode,
                 IN ULONG UniqueId)
 {
+  DPRINT("ScsiPortLogError()\n");
   UNIMPLEMENTED;
 }
 
@@ -619,6 +697,7 @@ ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension,
                           IN ULONG Offset,
                           IN ULONG Length)
 {
+  DPRINT("ScsiPortSetBusDataByOffset()\n");
   return(HalSetBusDataByOffset(BusDataType,
                               SystemIoBusNumber,
                               SlotNumber,
@@ -636,6 +715,7 @@ ScsiPortValidateRange(IN PVOID HwDeviceExtension,
                      IN ULONG NumberOfBytes,
                      IN BOOLEAN InIoSpace)
 {
+  DPRINT("ScsiPortValidateRange()\n");
   return(TRUE);
 }
 
@@ -1050,7 +1130,8 @@ ScsiPortStartPacket(IN OUT PVOID Context)
 static NTSTATUS
 ScsiPortCreatePortDevice(IN PDRIVER_OBJECT DriverObject,
                         IN PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension,
-                        IN ULONG PortNumber)
+                        IN ULONG PortNumber,
+                        IN OUT PSCSI_PORT_DEVICE_EXTENSION *RealDeviceExtension)
 {
   PSCSI_PORT_DEVICE_EXTENSION PortDeviceExtension;
   PIO_SCSI_CAPABILITIES PortCapabilities;
@@ -1061,23 +1142,20 @@ ScsiPortCreatePortDevice(IN PDRIVER_OBJECT DriverObject,
   UNICODE_STRING DosDeviceName;
   NTSTATUS Status;
   ULONG AccessRangeSize;
-
-#if 0
   ULONG MappedIrq;
   KIRQL Dirql;
   KAFFINITY Affinity;
-#endif
 
   DPRINT("ScsiPortCreatePortDevice() called\n");
 
-#if 0
+  *RealDeviceExtension = NULL;
+
   MappedIrq = HalGetInterruptVector(PseudoDeviceExtension->PortConfig.AdapterInterfaceType,
                                    PseudoDeviceExtension->PortConfig.SystemIoBusNumber,
-                                   0,
                                    PseudoDeviceExtension->PortConfig.BusInterruptLevel,
+                                   PseudoDeviceExtension->PortConfig.BusInterruptVector,
                                    &Dirql,
                                    &Affinity);
-#endif
 
   /* Create a unicode device name */
   swprintf(NameBuffer,
@@ -1124,6 +1202,23 @@ ScsiPortCreatePortDevice(IN PDRIVER_OBJECT DriverObject,
         PseudoDeviceExtension->PortConfig.AccessRanges,
         AccessRangeSize);
 
+  /* Copy device base list */
+  if (IsListEmpty(&PseudoDeviceExtension->DeviceBaseListHead))
+    {
+      InitializeListHead(&PortDeviceExtension->DeviceBaseListHead);
+    }
+  else
+    {
+      PseudoDeviceExtension->DeviceBaseListHead.Flink =
+       PortDeviceExtension->DeviceBaseListHead.Flink;
+      PseudoDeviceExtension->DeviceBaseListHead.Blink =
+       PortDeviceExtension->DeviceBaseListHead.Blink;
+      PortDeviceExtension->DeviceBaseListHead.Blink->Flink =
+       &PortDeviceExtension->DeviceBaseListHead;
+      PortDeviceExtension->DeviceBaseListHead.Flink->Blink =
+       &PortDeviceExtension->DeviceBaseListHead;
+    }
+
   PortDeviceExtension->DeviceObject = PortDeviceObject;
   PortDeviceExtension->PortNumber = PortNumber;
 
@@ -1136,12 +1231,12 @@ ScsiPortCreatePortDevice(IN PDRIVER_OBJECT DriverObject,
                              ScsiPortIsr,
                              PortDeviceExtension,
                              &PortDeviceExtension->SpinLock,
-                             PortDeviceExtension->PortConfig.BusInterruptVector, // MappedIrq,
-                             PortDeviceExtension->PortConfig.BusInterruptLevel, // Dirql,
-                             15, //Dirql,
+                             MappedIrq,
+                             Dirql,
+                             Dirql,
                              PortDeviceExtension->PortConfig.InterruptMode,
-                             FALSE,
-                             0xFFFF, //Affinity,
+                             TRUE,
+                             Affinity,
                              FALSE);
   if (!NT_SUCCESS(Status))
     {
@@ -1189,6 +1284,7 @@ ScsiPortCreatePortDevice(IN PDRIVER_OBJECT DriverObject,
 
   /* FIXME: Copy more configuration data? */
 
+
   /* Create the dos device link */
   swprintf(DosNameBuffer,
           L"\\??\\Scsi%lu:",
@@ -1199,6 +1295,8 @@ ScsiPortCreatePortDevice(IN PDRIVER_OBJECT DriverObject,
   IoCreateSymbolicLink(&DosDeviceName,
                       &DeviceName);
 
+  *RealDeviceExtension = PortDeviceExtension;
+
   DPRINT("ScsiPortCreatePortDevice() done\n");
 
   return(STATUS_SUCCESS);
@@ -1241,9 +1339,10 @@ ScsiPortInquire(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
     {
       Srb.PathId = Bus;
 
-      AdapterInfo->BusData[Bus].InitiatorBusId = 0;    /* ? */
+      AdapterInfo->BusData[Bus].InitiatorBusId =
+       DeviceExtension->PortConfig.InitiatorBusId[Bus];
       AdapterInfo->BusData[Bus].InquiryDataOffset =
-        (ULONG)((PUCHAR)UnitInfo - (PUCHAR)AdapterInfo);
+       (ULONG)((PUCHAR)UnitInfo - (PUCHAR)AdapterInfo);
 
       PrevUnit = NULL;
       UnitCount = 0;
@@ -1499,31 +1598,71 @@ ScsiPortFreeSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
 }
 
 
-#if 0
+/**********************************************************************
+ * NAME                                                        INTERNAL
+ *     ScsiPortBuildDeviceMap
+ *
+ * DESCRIPTION
+ *     Builds the registry device map of all device which are attached
+ *     to the given SCSI HBA port. The device map is located at:
+ *       \Registry\Machine\DeviceMap\Scsi
+ *
+ * RUN LEVEL
+ *     PASSIVE_LEVEL
+ *
+ * ARGUMENTS
+ *     DeviceExtension
+ *             ...
+ *
+ *     RegistryPath
+ *             Name of registry driver service key.
+ *
+ * RETURNS
+ *     NTSTATUS
+ */
+
 static NTSTATUS
-ScsiPortBuildDeviceMap(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
+ScsiPortBuildDeviceMap(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+                      PUNICODE_STRING RegistryPath)
 {
   OBJECT_ATTRIBUTES ObjectAttributes;
   UNICODE_STRING KeyName;
-  WCHAR NameBuffer[32];
+  UNICODE_STRING ValueName;
+  WCHAR NameBuffer[64];
   ULONG Disposition;
   HANDLE ScsiKey;
   HANDLE ScsiPortKey;
   HANDLE ScsiBusKey;
+  HANDLE ScsiInitiatorKey;
   HANDLE ScsiTargetKey;
-  HANDLE ScsiUnitKey;
+  HANDLE ScsiLunKey;
   ULONG BusNumber;
+  UCHAR CurrentTarget;
+  PSCSI_ADAPTER_BUS_INFO AdapterInfo;
+  PSCSI_INQUIRY_DATA UnitInfo;
+  PINQUIRYDATA InquiryData;
+  PWCHAR DriverName;
+  ULONG UlongData;
+  PWCHAR TypeName;
   NTSTATUS Status;
 
+  DPRINT("ScsiPortBuildDeviceMap() called\n");
+
+  if (DeviceExtension == NULL || RegistryPath == NULL)
+    {
+      DPRINT1("Invalid parameter\n");
+      return(STATUS_INVALID_PARAMETER);
+    }
+
   /* Open or create the 'Scsi' subkey */
   RtlInitUnicodeStringFromLiteral(&KeyName,
-       L"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
+                                 L"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
   InitializeObjectAttributes(&ObjectAttributes,
                             &KeyName,
-                            OBJ_OPENIF,
+                            OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
                             0,
                             NULL);
-  Status = NtCreateKey(&ScsiKey,
+  Status = ZwCreateKey(&ScsiKey,
                       KEY_ALL_ACCESS,
                       &ObjectAttributes,
                       0,
@@ -1531,9 +1670,15 @@ ScsiPortBuildDeviceMap(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
                       REG_OPTION_VOLATILE,
                       &Disposition);
   if (!NT_SUCCESS(Status))
-    return(Status);
+    {
+      DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
+      return(Status);
+    }
 
   /* Create new 'Scsi Port X' subkey */
+  DPRINT("Scsi Port %lu\n",
+        DeviceExtension->PortNumber);
+
   swprintf(NameBuffer,
           L"Scsi Port %lu",
           DeviceExtension->PortNumber);
@@ -1544,73 +1689,345 @@ ScsiPortBuildDeviceMap(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
                             0,
                             ScsiKey,
                             NULL);
-  Status = NtCreateKey(&ScsiPortKey,
+  Status = ZwCreateKey(&ScsiPortKey,
                       KEY_ALL_ACCESS,
                       &ObjectAttributes,
                       0,
                       NULL,
                       REG_OPTION_VOLATILE,
                       &Disposition);
+  ZwClose(ScsiKey);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
+      return(Status);
+    }
+
+  /*
+   * Create port-specific values
+   */
+
+  /* Set 'DMA Enabled' (REG_DWORD) value */
+  UlongData = (ULONG)!DeviceExtension->PortCapabilities->AdapterUsesPio;
+  DPRINT("  DMA Enabled = %s\n", (UlongData) ? "TRUE" : "FALSE");
+  RtlInitUnicodeString(&ValueName,
+                      L"DMA Enabled");
+  Status = ZwSetValueKey(ScsiPortKey,
+                        &ValueName,
+                        0,
+                        REG_DWORD,
+                        &UlongData,
+                        sizeof(ULONG));
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT("ZwSetValueKey('DMA Enabled') failed (Status %lx)\n", Status);
+      ZwClose(ScsiPortKey);
+      return(Status);
+    }
+
+  /* Set 'Driver' (REG_SZ) value */
+  DriverName = wcsrchr(RegistryPath->Buffer, L'\\') + 1;
+  DPRINT("  Driver = '%S'\n", DriverName);
+  RtlInitUnicodeString(&ValueName,
+                      L"Driver");
+  Status = ZwSetValueKey(ScsiPortKey,
+                        &ValueName,
+                        0,
+                        REG_SZ,
+                        DriverName,
+                        wcslen(DriverName) * sizeof(WCHAR));
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT("ZwSetValueKey('Driver') failed (Status %lx)\n", Status);
+      ZwClose(ScsiPortKey);
+      return(Status);
+    }
+
+  /* Set 'Interrupt' (REG_DWORD) value (NT4 only) */
+  UlongData = (ULONG)DeviceExtension->PortConfig.BusInterruptLevel;
+  DPRINT("  Interrupt = %lu\n", UlongData);
+  RtlInitUnicodeString(&ValueName,
+                      L"Interrupt");
+  Status = ZwSetValueKey(ScsiPortKey,
+                        &ValueName,
+                        0,
+                        REG_DWORD,
+                        &UlongData,
+                        sizeof(ULONG));
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT("ZwSetValueKey('Interrupt') failed (Status %lx)\n", Status);
+      ZwClose(ScsiPortKey);
+      return(Status);
+    }
+
+  /* Set 'IOAddress' (REG_DWORD) value (NT4 only) */
+  UlongData = ScsiPortConvertPhysicalAddressToUlong(DeviceExtension->PortConfig.AccessRanges[0].RangeStart);
+  DPRINT("  IOAddress = %lx\n", UlongData);
+  RtlInitUnicodeString(&ValueName,
+                      L"IOAddress");
+  Status = ZwSetValueKey(ScsiPortKey,
+                        &ValueName,
+                        0,
+                        REG_DWORD,
+                        &UlongData,
+                        sizeof(ULONG));
   if (!NT_SUCCESS(Status))
     {
-      NtClose(ScsiKey);
+      DPRINT("ZwSetValueKey('IOAddress') failed (Status %lx)\n", Status);
+      ZwClose(ScsiPortKey);
       return(Status);
     }
 
-  /* Add port-specific values */
+  /* Enumerate buses */
+  for (BusNumber = 0; BusNumber < DeviceExtension->PortConfig.NumberOfBuses; BusNumber++)
+    {
+      /* Create 'Scsi Bus X' key */
+      DPRINT("    Scsi Bus %lu\n", BusNumber);
+      swprintf(NameBuffer,
+              L"Scsi Bus %lu",
+              BusNumber);
+      RtlInitUnicodeString(&KeyName,
+                          NameBuffer);
+      InitializeObjectAttributes(&ObjectAttributes,
+                                &KeyName,
+                                0,
+                                ScsiPortKey,
+                                NULL);
+      Status = ZwCreateKey(&ScsiBusKey,
+                          KEY_ALL_ACCESS,
+                          &ObjectAttributes,
+                          0,
+                          NULL,
+                          REG_OPTION_VOLATILE,
+                          &Disposition);
+      if (!NT_SUCCESS(Status))
+       {
+         DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
+         ZwClose(ScsiPortKey);
+         return(Status);
+       }
 
-  /* 'DMA Enabled' (REG_DWORD) */
-  DPRINT1("DMA Enabled = %s\n",
-         (DeviceExtension->PortCapabilities->AdapterUsesPio)?"TRUE":"FALSE");
+      /* Create 'Initiator Id X' key */
+      DPRINT("      Initiator Id %u\n",
+             DeviceExtension->PortConfig.InitiatorBusId[BusNumber]);
+      swprintf(NameBuffer,
+              L"Initiator Id %u",
+              DeviceExtension->PortConfig.InitiatorBusId[BusNumber]);
+      RtlInitUnicodeString(&KeyName,
+                          NameBuffer);
+      InitializeObjectAttributes(&ObjectAttributes,
+                                &KeyName,
+                                0,
+                                ScsiBusKey,
+                                NULL);
+      Status = ZwCreateKey(&ScsiInitiatorKey,
+                          KEY_ALL_ACCESS,
+                          &ObjectAttributes,
+                          0,
+                          NULL,
+                          REG_OPTION_VOLATILE,
+                          &Disposition);
+      if (!NT_SUCCESS(Status))
+       {
+         DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
+         ZwClose(ScsiBusKey);
+         ZwClose(ScsiPortKey);
+         return(Status);
+       }
 
-  /* 'Driver' (REG_SZ) */
+      /* FIXME: Are there any initiator values (??) */
 
-  /* 'Interrupt' (REG_DWORD) (NT4 only) */
-  DPRINT1("Interrupt = %lx\n", DeviceExtension->PortConfig.BusInterruptLevel);
+      ZwClose(ScsiInitiatorKey);
 
-  /* 'IOAddress' (REG_DWORD) (NT4 only) */
-  DPRINT1("IOAddress = %lx\n",
-         ScsiPortConvertPhysicalAddressToUlong(DeviceExtension->PortConfig.AccessRanges[0].RangeStart));
 
+      /* Enumerate targets */
+      CurrentTarget = (UCHAR)-1;
+      ScsiTargetKey = NULL;
+      AdapterInfo = (PSCSI_ADAPTER_BUS_INFO)DeviceExtension->PortBusInfo;
+      if (AdapterInfo->BusData[BusNumber].NumberOfLogicalUnits != 0)
+       {
+         UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)AdapterInfo +
+           AdapterInfo->BusData[BusNumber].InquiryDataOffset);
 
-  /* Create 'Scsi Bus X' keys */
-  for (BusNumber = 0; BusNumber < DeviceExtension->PortConfig.NumberOfBuses; BusNumber++)
-     {
-       swprintf(NameBuffer,
-                L"Scsi Bus %lu",
-                DeviceExtension->PortNumber);
-       RtlInitUnicodeString(&KeyName,
-                            NameBuffer);
-       InitializeObjectAttributes(&ObjectAttributes,
-                                  &KeyName,
+         while (AdapterInfo->BusData[BusNumber].InquiryDataOffset)
+           {
+             if (UnitInfo->TargetId != CurrentTarget)
+               {
+                 /* Close old target key */
+                 if (ScsiTargetKey != NULL)
+                   {
+                     ZwClose(ScsiTargetKey);
+                     ScsiTargetKey = NULL;
+                   }
+
+                 /* Create 'Target Id X' key */
+                 DPRINT("      Target Id %u\n",
+                        UnitInfo->TargetId);
+                 swprintf(NameBuffer,
+                          L"Target Id %u",
+                          UnitInfo->TargetId);
+                 RtlInitUnicodeString(&KeyName,
+                                      NameBuffer);
+                 InitializeObjectAttributes(&ObjectAttributes,
+                                            &KeyName,
+                                            0,
+                                            ScsiBusKey,
+                                            NULL);
+                 Status = ZwCreateKey(&ScsiTargetKey,
+                                      KEY_ALL_ACCESS,
+                                      &ObjectAttributes,
+                                      0,
+                                      NULL,
+                                      REG_OPTION_VOLATILE,
+                                      &Disposition);
+                 if (!NT_SUCCESS(Status))
+                   {
+                     DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
+                     ZwClose(ScsiBusKey);
+                     ZwClose(ScsiPortKey);
+                     return(Status);
+                   }
+
+                 CurrentTarget = UnitInfo->TargetId;
+               }
+
+             /* Create 'Logical Unit Id X' key */
+             DPRINT("        Logical Unit Id %u\n",
+                    UnitInfo->Lun);
+             swprintf(NameBuffer,
+                      L"Logical Unit Id %u",
+                      UnitInfo->Lun);
+             RtlInitUnicodeString(&KeyName,
+                                  NameBuffer);
+             InitializeObjectAttributes(&ObjectAttributes,
+                                        &KeyName,
+                                        0,
+                                        ScsiTargetKey,
+                                        NULL);
+             Status = ZwCreateKey(&ScsiLunKey,
+                                  KEY_ALL_ACCESS,
+                                  &ObjectAttributes,
                                   0,
-                                  ScsiPortKey,
-                                  NULL);
-       Status = NtCreateKey(&ScsiBusKey,
-                            KEY_ALL_ACCESS,
-                            &ObjectAttributes,
-                            0,
-                            NULL,
-                            REG_OPTION_VOLATILE,
-                            &Disposition);
-       if (!NT_SUCCESS(Status))
-         {
-           NtClose(ScsiPortKey);
-           NtClose(ScsiKey);
-           return(Status);
-         }
+                                  NULL,
+                                  REG_OPTION_VOLATILE,
+                                  &Disposition);
+             if (!NT_SUCCESS(Status))
+               {
+                 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
+                 ZwClose(ScsiTargetKey);
+                 ZwClose(ScsiBusKey);
+                 ZwClose(ScsiPortKey);
+                 return(Status);
+               }
 
-       /* Create target keys */
+             /* Set values for logical unit */
+             InquiryData = (PINQUIRYDATA)UnitInfo->InquiryData;
+
+             /* Set 'Identifier' (REG_SZ) value */
+             swprintf(NameBuffer,
+                      L"%.8S%.16S%.4S",
+                      InquiryData->VendorId,
+                      InquiryData->ProductId,
+                      InquiryData->ProductRevisionLevel);
+             DPRINT("          Identifier = '%S'\n",
+                    NameBuffer);
+             RtlInitUnicodeString(&ValueName,
+                                  L"Identifier");
+             Status = ZwSetValueKey(ScsiLunKey,
+                                    &ValueName,
+                                    0,
+                                    REG_SZ,
+                                    NameBuffer,
+                                    wcslen(NameBuffer) * sizeof(WCHAR));
+             if (!NT_SUCCESS(Status))
+               {
+                 DPRINT("ZwSetValueKey('Identifier') failed (Status %lx)\n", Status);
+                 ZwClose(ScsiLunKey);
+                 ZwClose(ScsiTargetKey);
+                 ZwClose(ScsiBusKey);
+                 ZwClose(ScsiPortKey);
+                 return(Status);
+               }
 
+             /* Set 'Type' (REG_SZ) value */
+             switch (InquiryData->DeviceType)
+               {
+                 case 0:
+                   TypeName = L"DiskPeripheral";
+                   break;
+                 case 1:
+                   TypeName = L"TapePeripheral";
+                   break;
+                 case 2:
+                   TypeName = L"PrinterPeripheral";
+                   break;
+                 case 4:
+                   TypeName = L"WormPeripheral";
+                   break;
+                 case 5:
+                   TypeName = L"CdRomPeripheral";
+                   break;
+                 case 6:
+                   TypeName = L"ScannerPeripheral";
+                   break;
+                 case 7:
+                   TypeName = L"OpticalDiskPeripheral";
+                   break;
+                 case 8:
+                   TypeName = L"MediumChangerPeripheral";
+                   break;
+                 case 9:
+                   TypeName = L"CommunicationPeripheral";
+                   break;
+                 default:
+                   TypeName = L"OtherPeripheral";
+                   break;
+               }
+             DPRINT("          Type = '%S'\n", TypeName);
+             RtlInitUnicodeString(&ValueName,
+                                  L"Type");
+             Status = ZwSetValueKey(ScsiLunKey,
+                                    &ValueName,
+                                    0,
+                                    REG_SZ,
+                                    TypeName,
+                                    wcslen(TypeName) * sizeof(WCHAR));
+             if (!NT_SUCCESS(Status))
+               {
+                 DPRINT("ZwSetValueKey('Type') failed (Status %lx)\n", Status);
+                 ZwClose(ScsiLunKey);
+                 ZwClose(ScsiTargetKey);
+                 ZwClose(ScsiBusKey);
+                 ZwClose(ScsiPortKey);
+                 return(Status);
+               }
 
-       NtClose(ScsiBusKey);
+             ZwClose(ScsiLunKey);
+
+             if (UnitInfo->NextInquiryDataOffset == 0)
+               break;
+
+             UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)AdapterInfo +
+               UnitInfo->NextInquiryDataOffset);
+           }
+
+         /* Close old target key */
+         if (ScsiTargetKey != NULL)
+           {
+             ZwClose(ScsiTargetKey);
+             ScsiTargetKey = NULL;
+           }
+       }
+
+       ZwClose(ScsiBusKey);
      }
 
-  NtClose(ScsiPortKey);
-  NtClose(ScsiKey);
+  ZwClose(ScsiPortKey);
+
+  DPRINT("ScsiPortBuildDeviceMap() done\n");
 
   return(Status);
 }
-#endif
 
 /* EOF */