3 * Copyright (C) 2001, 2002 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * FILE: services/storage/scsiport/scsiport.c
24 * PURPOSE: SCSI port driver
25 * PROGRAMMER: Eric Kohl (ekohl@rz-online.de)
28 /* INCLUDES *****************************************************************/
30 #include <ddk/ntddk.h>
33 #include <ddk/ntddscsi.h>
39 #define VERSION "0.0.1"
42 /* TYPES *********************************************************************/
45 * SCSI_PORT_TIMER_STATES
48 * An enumeration containing the states in the timer DFA
50 typedef enum _SCSI_PORT_TIMER_STATES
54 IDETimerResetWaitForBusyNegate,
55 IDETimerResetWaitForDrdyAssert
56 } SCSI_PORT_TIMER_STATES;
59 typedef struct _SCSI_PORT_DEVICE_BASE
65 SCSI_PHYSICAL_ADDRESS IoAddress;
66 ULONG SystemIoBusNumber;
67 } SCSI_PORT_DEVICE_BASE, *PSCSI_PORT_DEVICE_BASE;
71 * SCSI_PORT_DEVICE_EXTENSION
74 * First part of the port objects device extension. The second
75 * part is the miniport-specific device extension.
78 typedef struct _SCSI_PORT_DEVICE_EXTENSION
81 ULONG MiniPortExtensionSize;
82 PORT_CONFIGURATION_INFORMATION PortConfig;
87 PKINTERRUPT Interrupt;
91 SCSI_PORT_TIMER_STATES TimerState;
96 LIST_ENTRY DeviceBaseListHead;
98 ULONG PortBusInfoSize;
99 PSCSI_ADAPTER_BUS_INFO PortBusInfo;
101 PIO_SCSI_CAPABILITIES PortCapabilities;
103 PDEVICE_OBJECT DeviceObject;
104 PCONTROLLER_OBJECT ControllerObject;
106 PHW_STARTIO HwStartIo;
107 PHW_INTERRUPT HwInterrupt;
109 PSCSI_REQUEST_BLOCK OriginalSrb;
110 SCSI_REQUEST_BLOCK InternalSrb;
111 SENSE_DATA InternalSenseData;
113 UCHAR MiniPortDeviceExtension[1]; /* must be the last entry */
114 } SCSI_PORT_DEVICE_EXTENSION, *PSCSI_PORT_DEVICE_EXTENSION;
117 #define IRP_FLAG_COMPLETE 0x00000001
118 #define IRP_FLAG_NEXT 0x00000002
121 /* GLOBALS *******************************************************************/
123 static NTSTATUS STDCALL
124 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
127 static NTSTATUS STDCALL
128 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject,
131 static NTSTATUS STDCALL
132 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
136 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject,
139 static IO_ALLOCATION_ACTION STDCALL
140 ScsiPortAllocateController(IN PDEVICE_OBJECT DeviceObject,
142 IN PVOID MapRegisterBase,
145 static BOOLEAN STDCALL
146 ScsiPortStartPacket(IN OUT PVOID Context);
149 ScsiPortCreatePortDevice(IN PDRIVER_OBJECT DriverObject,
150 IN PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension,
152 IN OUT PSCSI_PORT_DEVICE_EXTENSION *RealDeviceExtension);
155 ScsiPortInquire(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
157 static BOOLEAN STDCALL
158 ScsiPortIsr(IN PKINTERRUPT Interrupt,
159 IN PVOID ServiceContext);
162 ScsiPortDpcForIsr(IN PKDPC Dpc,
163 IN PDEVICE_OBJECT DpcDeviceObject,
165 IN PVOID DpcContext);
168 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
171 static PSCSI_REQUEST_BLOCK
172 ScsiPortInitSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
173 PSCSI_REQUEST_BLOCK OriginalSrb);
176 ScsiPortBuildDeviceMap(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
177 PUNICODE_STRING RegistryPath);
180 /* FUNCTIONS *****************************************************************/
182 /**********************************************************************
187 * This function initializes the driver.
194 * System allocated Driver Object for this driver.
197 * Name of registry driver service key.
204 DriverEntry(IN PDRIVER_OBJECT DriverObject,
205 IN PUNICODE_STRING RegistryPath)
207 DPRINT("ScsiPort Driver %s\n", VERSION);
208 return(STATUS_SUCCESS);
212 /**********************************************************************
217 * Prints debugging messages.
224 * Debug level of the given message.
227 * Pointer to printf()-compatible format string.
230 Additional output data (see printf()).
237 ScsiDebugPrint(IN ULONG DebugPrintLevel,
238 IN PCHAR DebugMessage,
245 if (DebugPrintLevel > InternalDebugLevel)
249 va_start(ap, DebugMessage);
250 vsprintf(Buffer, DebugMessage, ap);
258 ScsiPortCompleteRequest(IN PVOID HwDeviceExtension,
264 DPRINT("ScsiPortCompleteRequest()\n");
270 ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address)
272 DPRINT("ScsiPortConvertPhysicalAddressToUlong()\n");
273 return(Address.u.LowPart);
278 ScsiPortFlushDma(IN PVOID HwDeviceExtension)
280 DPRINT("ScsiPortFlushDma()\n");
286 ScsiPortFreeDeviceBase(IN PVOID HwDeviceExtension,
287 IN PVOID MappedAddress)
289 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
290 PSCSI_PORT_DEVICE_BASE DeviceBase;
293 DPRINT("ScsiPortFreeDeviceBase() called\n");
295 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
296 SCSI_PORT_DEVICE_EXTENSION,
297 MiniPortDeviceExtension);
298 if (IsListEmpty(&DeviceExtension->DeviceBaseListHead))
301 Entry = DeviceExtension->DeviceBaseListHead.Flink;
302 while (Entry != &DeviceExtension->DeviceBaseListHead)
304 DeviceBase = CONTAINING_RECORD(Entry,
305 SCSI_PORT_DEVICE_BASE,
307 if (DeviceBase->MappedAddress == MappedAddress)
309 MmUnmapIoSpace(DeviceBase->MappedAddress,
310 DeviceBase->NumberOfBytes);
311 RemoveEntryList(Entry);
312 ExFreePool(DeviceBase);
317 Entry = Entry->Flink;
323 ScsiPortGetBusData(IN PVOID DeviceExtension,
324 IN ULONG BusDataType,
325 IN ULONG SystemIoBusNumber,
330 return(HalGetBusData(BusDataType,
339 ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension,
340 IN INTERFACE_TYPE BusType,
341 IN ULONG SystemIoBusNumber,
342 IN SCSI_PHYSICAL_ADDRESS IoAddress,
343 IN ULONG NumberOfBytes,
344 IN BOOLEAN InIoSpace)
346 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
347 PHYSICAL_ADDRESS TranslatedAddress;
348 PSCSI_PORT_DEVICE_BASE DeviceBase;
352 DPRINT("ScsiPortGetDeviceBase() called\n");
354 AddressSpace = (ULONG)InIoSpace;
355 if (HalTranslateBusAddress(BusType,
359 &TranslatedAddress) == FALSE)
363 if (AddressSpace != 0)
364 return((PVOID)TranslatedAddress.u.LowPart);
366 MappedAddress = MmMapIoSpace(TranslatedAddress,
370 DeviceBase = ExAllocatePool(NonPagedPool,
371 sizeof(SCSI_PORT_DEVICE_BASE));
372 if (DeviceBase == NULL)
373 return(MappedAddress);
375 DeviceBase->MappedAddress = MappedAddress;
376 DeviceBase->NumberOfBytes = NumberOfBytes;
377 DeviceBase->IoAddress = IoAddress;
378 DeviceBase->SystemIoBusNumber = SystemIoBusNumber;
380 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
381 SCSI_PORT_DEVICE_EXTENSION,
382 MiniPortDeviceExtension);
384 InsertHeadList(&DeviceExtension->DeviceBaseListHead,
387 return(MappedAddress);
392 ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension,
397 DPRINT("ScsiPortGetLogicalUnit()\n");
402 SCSI_PHYSICAL_ADDRESS STDCALL
403 ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension,
404 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
405 IN PVOID VirtualAddress,
408 DPRINT("ScsiPortGetPhysicalAddress()\n");
413 PSCSI_REQUEST_BLOCK STDCALL
414 ScsiPortGetSrb(IN PVOID DeviceExtension,
420 DPRINT("ScsiPortGetSrb()\n");
426 ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension,
427 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
428 IN ULONG NumberOfBytes)
430 DPRINT("ScsiPortGetUncachedExtension()\n");
436 ScsiPortGetVirtualAddress(IN PVOID HwDeviceExtension,
437 IN SCSI_PHYSICAL_ADDRESS PhysicalAddress)
439 DPRINT("ScsiPortGetVirtualAddress()\n");
444 /**********************************************************************
449 * Initializes SCSI port driver specific data.
456 * Pointer to the miniport driver's driver object.
459 * Pointer to the miniport driver's registry path.
461 * HwInitializationData
462 * Pointer to port driver specific configuration data.
465 Miniport driver specific context.
472 ScsiPortInitialize(IN PVOID Argument1,
474 IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
477 PDRIVER_OBJECT DriverObject = (PDRIVER_OBJECT)Argument1;
478 PUNICODE_STRING RegistryPath = (PUNICODE_STRING)Argument2;
479 PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension;
480 PSCSI_PORT_DEVICE_EXTENSION RealDeviceExtension;
481 PCONFIGURATION_INFORMATION SystemConfig;
482 PPORT_CONFIGURATION_INFORMATION PortConfig;
488 PACCESS_RANGE AccessRanges;
491 DPRINT("ScsiPortInitialize() called!\n");
493 if ((HwInitializationData->HwInitialize == NULL) ||
494 (HwInitializationData->HwStartIo == NULL) ||
495 (HwInitializationData->HwInterrupt == NULL) ||
496 (HwInitializationData->HwFindAdapter == NULL) ||
497 (HwInitializationData->HwResetBus == NULL))
498 return(STATUS_INVALID_PARAMETER);
500 DriverObject->DriverStartIo = ScsiPortStartIo;
501 DriverObject->MajorFunction[IRP_MJ_CREATE] = ScsiPortCreateClose;
502 DriverObject->MajorFunction[IRP_MJ_CLOSE] = ScsiPortCreateClose;
503 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiPortDeviceControl;
504 DriverObject->MajorFunction[IRP_MJ_SCSI] = ScsiPortDispatchScsi;
507 SystemConfig = IoGetConfigurationInformation();
509 ExtensionSize = sizeof(SCSI_PORT_DEVICE_EXTENSION) +
510 HwInitializationData->DeviceExtensionSize;
511 PseudoDeviceExtension = ExAllocatePool(PagedPool,
513 RtlZeroMemory(PseudoDeviceExtension,
515 PseudoDeviceExtension->Length = ExtensionSize;
516 PseudoDeviceExtension->MiniPortExtensionSize = HwInitializationData->DeviceExtensionSize;
517 PseudoDeviceExtension->HwStartIo = HwInitializationData->HwStartIo;
518 PseudoDeviceExtension->HwInterrupt = HwInitializationData->HwInterrupt;
520 PortConfig = &PseudoDeviceExtension->PortConfig;
522 PortConfig->Length = sizeof(PORT_CONFIGURATION_INFORMATION);
523 PortConfig->AdapterInterfaceType = HwInitializationData->AdapterInterfaceType;
524 PortConfig->InterruptMode =
525 (PortConfig->AdapterInterfaceType == PCIBus) ? LevelSensitive : Latched;
526 PortConfig->AtdiskPrimaryClaimed = SystemConfig->AtDiskPrimaryAddressClaimed;
527 PortConfig->AtdiskSecondaryClaimed = SystemConfig->AtDiskSecondaryAddressClaimed;
528 PortConfig->NumberOfAccessRanges = HwInitializationData->NumberOfAccessRanges;
530 PortConfig->AccessRanges =
531 ExAllocatePool(PagedPool,
532 sizeof(ACCESS_RANGE) * PortConfig->NumberOfAccessRanges);
534 for (i = 0; i < SCSI_MAXIMUM_BUSES; i++)
535 PortConfig->InitiatorBusId[i] = 255;
537 PortConfig->SystemIoBusNumber = 0;
538 PortConfig->SlotNumber = 0;
540 MaxBus = (PortConfig->AdapterInterfaceType == PCIBus) ? 8 : 1;
542 DPRINT("MaxBus: %lu\n", MaxBus);
546 DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig->SystemIoBusNumber);
548 InitializeListHead(&PseudoDeviceExtension->DeviceBaseListHead);
550 // RtlZeroMemory(AccessRanges,
551 // sizeof(ACCESS_RANGE) * PortConfig->NumberOfAccessRanges);
553 RtlZeroMemory(PseudoDeviceExtension->MiniPortDeviceExtension,
554 PseudoDeviceExtension->MiniPortExtensionSize);
556 /* Note: HwFindAdapter is called once for each bus */
557 Result = (HwInitializationData->HwFindAdapter)(&PseudoDeviceExtension->MiniPortDeviceExtension,
559 NULL, /* BusInformation */
560 NULL, /* ArgumentString */
561 &PseudoDeviceExtension->PortConfig,
563 DPRINT("HwFindAdapter() result: %lu\n", Result);
565 if (Result == SP_RETURN_FOUND)
567 DPRINT("ScsiPortInitialize(): Found HBA!\n");
569 Status = ScsiPortCreatePortDevice(DriverObject,
570 PseudoDeviceExtension,
571 SystemConfig->ScsiPortCount,
572 &RealDeviceExtension);
574 if (!NT_SUCCESS(Status))
576 DbgPrint("ScsiPortCreatePortDevice() failed! (Status 0x%lX)\n", Status);
578 ExFreePool(PortConfig->AccessRanges);
579 ExFreePool(PseudoDeviceExtension);
584 /* Build the registry device map */
585 ScsiPortBuildDeviceMap(RealDeviceExtension,
586 (PUNICODE_STRING)Argument2);
588 /* Update the configuration info */
589 SystemConfig->AtDiskPrimaryAddressClaimed = PortConfig->AtdiskPrimaryClaimed;
590 SystemConfig->AtDiskSecondaryAddressClaimed = PortConfig->AtdiskSecondaryClaimed;
591 SystemConfig->ScsiPortCount++;
596 PortConfig->SystemIoBusNumber++;
597 PortConfig->SlotNumber = 0;
600 DPRINT("Bus: %lu MaxBus: %lu\n", PortConfig->SystemIoBusNumber, MaxBus);
601 if (PortConfig->SystemIoBusNumber >= MaxBus)
603 DPRINT("Scanned all buses!\n");
608 ExFreePool(PortConfig->AccessRanges);
609 ExFreePool(PseudoDeviceExtension);
611 DPRINT("ScsiPortInitialize() done!\n");
613 return(STATUS_SUCCESS);
618 ScsiPortIoMapTransfer(IN PVOID HwDeviceExtension,
619 IN PSCSI_REQUEST_BLOCK Srb,
620 IN ULONG LogicalAddress,
623 DPRINT("ScsiPortIoMapTransfer()\n");
629 ScsiPortLogError(IN PVOID HwDeviceExtension,
630 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
637 DPRINT("ScsiPortLogError()\n");
643 ScsiPortMoveMemory(OUT PVOID Destination,
647 RtlMoveMemory(Destination,
654 ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType,
655 IN PVOID HwDeviceExtension,
658 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
660 DPRINT("ScsiPortNotification() called\n");
662 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
663 SCSI_PORT_DEVICE_EXTENSION,
664 MiniPortDeviceExtension);
666 DPRINT("DeviceExtension %p\n", DeviceExtension);
668 DPRINT("Initializing = %s\n", (DeviceExtension->Initializing)?"TRUE":"FALSE");
670 if (DeviceExtension->Initializing == TRUE)
673 switch (NotificationType)
675 case RequestComplete:
676 DPRINT("Notify: RequestComplete\n");
677 DeviceExtension->IrpFlags |= IRP_FLAG_COMPLETE;
681 DPRINT("Notify: NextRequest\n");
682 DeviceExtension->IrpFlags |= IRP_FLAG_NEXT;
692 ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension,
693 IN ULONG BusDataType,
694 IN ULONG SystemIoBusNumber,
700 DPRINT("ScsiPortSetBusDataByOffset()\n");
701 return(HalSetBusDataByOffset(BusDataType,
711 ScsiPortValidateRange(IN PVOID HwDeviceExtension,
712 IN INTERFACE_TYPE BusType,
713 IN ULONG SystemIoBusNumber,
714 IN SCSI_PHYSICAL_ADDRESS IoAddress,
715 IN ULONG NumberOfBytes,
716 IN BOOLEAN InIoSpace)
718 DPRINT("ScsiPortValidateRange()\n");
723 /* INTERNAL FUNCTIONS ********************************************************/
725 /**********************************************************************
727 * ScsiPortCreateClose
730 * Answer requests for Create/Close calls: a null operation.
737 * Pointer to a device object.
743 Additional output data (see printf()).
749 static NTSTATUS STDCALL
750 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
753 DPRINT("ScsiPortCreateClose()\n");
755 Irp->IoStatus.Status = STATUS_SUCCESS;
756 Irp->IoStatus.Information = FILE_OPENED;
758 IoCompleteRequest(Irp, IO_NO_INCREMENT);
760 return(STATUS_SUCCESS);
764 /**********************************************************************
766 * ScsiPortDispatchScsi
769 * Answer requests for SCSI calls
775 * Standard dispatch arguments
781 static NTSTATUS STDCALL
782 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject,
785 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
786 PIO_STACK_LOCATION Stack;
787 PSCSI_REQUEST_BLOCK Srb;
788 NTSTATUS Status = STATUS_SUCCESS;
791 DPRINT("ScsiPortDispatchScsi(DeviceObject %p Irp %p)\n",
794 DeviceExtension = DeviceObject->DeviceExtension;
795 Stack = IoGetCurrentIrpStackLocation(Irp);
797 Srb = Stack->Parameters.Scsi.Srb;
800 Status = STATUS_UNSUCCESSFUL;
802 Irp->IoStatus.Status = Status;
803 Irp->IoStatus.Information = 0;
805 IoCompleteRequest(Irp, IO_NO_INCREMENT);
810 DPRINT("Srb: %p\n", Srb);
811 DPRINT("Srb->Function: %lu\n", Srb->Function);
812 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb->PathId, Srb->TargetId, Srb->Lun);
814 switch (Srb->Function)
816 case SRB_FUNCTION_EXECUTE_SCSI:
817 IoStartPacket(DeviceObject, Irp, NULL, NULL);
818 return(STATUS_PENDING);
820 case SRB_FUNCTION_SHUTDOWN:
821 case SRB_FUNCTION_FLUSH:
822 if (DeviceExtension->PortConfig.CachesData == TRUE)
824 IoStartPacket(DeviceObject, Irp, NULL, NULL);
825 return(STATUS_PENDING);
829 case SRB_FUNCTION_CLAIM_DEVICE:
831 PSCSI_ADAPTER_BUS_INFO AdapterInfo;
832 PSCSI_INQUIRY_DATA UnitInfo;
833 PINQUIRYDATA InquiryData;
835 DPRINT(" SRB_FUNCTION_CLAIM_DEVICE\n");
836 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb->PathId, Srb->TargetId, Srb->Lun);
838 Srb->DataBuffer = NULL;
840 if (DeviceExtension->PortBusInfo != NULL)
842 AdapterInfo = (PSCSI_ADAPTER_BUS_INFO)DeviceExtension->PortBusInfo;
844 if (AdapterInfo->BusData[Srb->PathId].NumberOfLogicalUnits == 0)
847 UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)AdapterInfo +
848 AdapterInfo->BusData[Srb->PathId].InquiryDataOffset);
850 while (AdapterInfo->BusData[Srb->PathId].InquiryDataOffset)
852 InquiryData = (PINQUIRYDATA)UnitInfo->InquiryData;
854 if ((UnitInfo->TargetId == Srb->TargetId) &&
855 (UnitInfo->Lun == Srb->Lun) &&
856 (UnitInfo->DeviceClaimed == FALSE))
858 UnitInfo->DeviceClaimed = TRUE;
859 DPRINT("Claimed device!\n");
861 /* FIXME: Hack!!!!! */
862 Srb->DataBuffer = DeviceObject;
867 if (UnitInfo->NextInquiryDataOffset == 0)
870 UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)AdapterInfo + UnitInfo->NextInquiryDataOffset);
876 case SRB_FUNCTION_RELEASE_DEVICE:
878 PSCSI_ADAPTER_BUS_INFO AdapterInfo;
879 PSCSI_INQUIRY_DATA UnitInfo;
880 PINQUIRYDATA InquiryData;
882 DPRINT(" SRB_FUNCTION_RELEASE_DEVICE\n");
883 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb->PathId, Srb->TargetId, Srb->Lun);
885 if (DeviceExtension->PortBusInfo != NULL)
887 AdapterInfo = (PSCSI_ADAPTER_BUS_INFO)DeviceExtension->PortBusInfo;
889 if (AdapterInfo->BusData[Srb->PathId].NumberOfLogicalUnits == 0)
892 UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)AdapterInfo +
893 AdapterInfo->BusData[Srb->PathId].InquiryDataOffset);
895 while (AdapterInfo->BusData[Srb->PathId].InquiryDataOffset)
897 InquiryData = (PINQUIRYDATA)UnitInfo->InquiryData;
899 if ((UnitInfo->TargetId == Srb->TargetId) &&
900 (UnitInfo->Lun == Srb->Lun) &&
901 (UnitInfo->DeviceClaimed == TRUE))
903 UnitInfo->DeviceClaimed = FALSE;
904 DPRINT("Released device!\n");
908 if (UnitInfo->NextInquiryDataOffset == 0)
911 UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)AdapterInfo + UnitInfo->NextInquiryDataOffset);
918 DPRINT1("SRB function not implemented (Function %lu)\n", Srb->Function);
919 Status = STATUS_NOT_IMPLEMENTED;
923 Irp->IoStatus.Status = Status;
924 Irp->IoStatus.Information = DataSize;
926 IoCompleteRequest(Irp, IO_NO_INCREMENT);
932 /**********************************************************************
934 * ScsiPortDeviceControl
937 * Answer requests for device control calls
943 * Standard dispatch arguments
949 static NTSTATUS STDCALL
950 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
953 PIO_STACK_LOCATION Stack;
954 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
956 DPRINT("ScsiPortDeviceControl()\n");
958 Irp->IoStatus.Status = STATUS_SUCCESS;
959 Irp->IoStatus.Information = 0;
962 Stack = IoGetCurrentIrpStackLocation(Irp);
963 DeviceExtension = DeviceObject->DeviceExtension;
965 switch (Stack->Parameters.DeviceIoControl.IoControlCode)
968 case IOCTL_SCSI_GET_CAPABILITIES:
970 DPRINT(" IOCTL_SCSI_GET_CAPABILITIES\n");
972 *((PIO_SCSI_CAPABILITIES *)Irp->AssociatedIrp.SystemBuffer) =
973 DeviceExtension->PortCapabilities;
975 Irp->IoStatus.Information = sizeof(PIO_SCSI_CAPABILITIES);
979 case IOCTL_SCSI_GET_INQUIRY_DATA:
981 DPRINT(" IOCTL_SCSI_GET_INQUIRY_DATA\n");
983 /* Copy inquiry data to the port device extension */
984 memcpy(Irp->AssociatedIrp.SystemBuffer,
985 DeviceExtension->PortBusInfo,
986 DeviceExtension->PortBusInfoSize);
988 DPRINT("BufferSize: %lu\n", DeviceExtension->PortBusInfoSize);
989 Irp->IoStatus.Information = DeviceExtension->PortBusInfoSize;
994 DPRINT1(" unknown ioctl code: 0x%lX\n",
995 Stack->Parameters.DeviceIoControl.IoControlCode);
999 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1001 return(STATUS_SUCCESS);
1006 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject,
1009 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1010 PIO_STACK_LOCATION IrpStack;
1013 DPRINT("ScsiPortStartIo() called!\n");
1015 DeviceExtension = DeviceObject->DeviceExtension;
1016 IrpStack = IoGetCurrentIrpStackLocation(Irp);
1018 // FIXME: implement the supported functions
1020 switch (IrpStack->MajorFunction)
1025 PSCSI_REQUEST_BLOCK Srb;
1028 DPRINT("IRP_MJ_SCSI\n");
1030 Srb = IrpStack->Parameters.Scsi.Srb;
1032 DPRINT("DeviceExtension %p\n", DeviceExtension);
1034 Irp->IoStatus.Status = STATUS_SUCCESS;
1035 Irp->IoStatus.Information = Srb->DataTransferLength;
1037 DeviceExtension->CurrentIrp = Irp;
1039 if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
1040 ScsiPortStartPacket,
1043 DPRINT("Synchronization failed!\n");
1045 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
1046 Irp->IoStatus.Information = 0;
1047 IoCompleteRequest(Irp,
1049 IoStartNextPacket(DeviceObject,
1052 KeAcquireSpinLock(&DeviceExtension->IrpLock, &oldIrql);
1053 if (DeviceExtension->IrpFlags & IRP_FLAG_COMPLETE)
1055 DeviceExtension->IrpFlags &= ~IRP_FLAG_COMPLETE;
1056 IoCompleteRequest(Irp,
1060 if (DeviceExtension->IrpFlags & IRP_FLAG_NEXT)
1062 DeviceExtension->IrpFlags &= ~IRP_FLAG_NEXT;
1063 KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
1064 IoStartNextPacket(DeviceObject,
1069 KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
1075 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
1076 Irp->IoStatus.Information = 0;
1077 IoCompleteRequest(Irp,
1079 IoStartNextPacket(DeviceObject,
1083 DPRINT("ScsiPortStartIo() done\n");
1087 static BOOLEAN STDCALL
1088 ScsiPortStartPacket(IN OUT PVOID Context)
1090 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1091 PIO_STACK_LOCATION IrpStack;
1092 PSCSI_REQUEST_BLOCK Srb;
1094 DPRINT("ScsiPortStartPacket() called\n");
1096 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)Context;
1098 IrpStack = IoGetCurrentIrpStackLocation(DeviceExtension->CurrentIrp);
1099 Srb = IrpStack->Parameters.Scsi.Srb;
1101 return(DeviceExtension->HwStartIo(&DeviceExtension->MiniPortDeviceExtension,
1106 /**********************************************************************
1108 * ScsiPortCreatePortDevice
1111 * Creates and initializes a SCSI port device object.
1120 * PseudoDeviceExtension
1131 ScsiPortCreatePortDevice(IN PDRIVER_OBJECT DriverObject,
1132 IN PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension,
1133 IN ULONG PortNumber,
1134 IN OUT PSCSI_PORT_DEVICE_EXTENSION *RealDeviceExtension)
1136 PSCSI_PORT_DEVICE_EXTENSION PortDeviceExtension;
1137 PIO_SCSI_CAPABILITIES PortCapabilities;
1138 PDEVICE_OBJECT PortDeviceObject;
1139 WCHAR NameBuffer[80];
1140 UNICODE_STRING DeviceName;
1141 WCHAR DosNameBuffer[80];
1142 UNICODE_STRING DosDeviceName;
1144 ULONG AccessRangeSize;
1149 DPRINT("ScsiPortCreatePortDevice() called\n");
1151 *RealDeviceExtension = NULL;
1153 MappedIrq = HalGetInterruptVector(PseudoDeviceExtension->PortConfig.AdapterInterfaceType,
1154 PseudoDeviceExtension->PortConfig.SystemIoBusNumber,
1155 PseudoDeviceExtension->PortConfig.BusInterruptLevel,
1156 PseudoDeviceExtension->PortConfig.BusInterruptVector,
1160 /* Create a unicode device name */
1161 swprintf(NameBuffer,
1162 L"\\Device\\ScsiPort%lu",
1164 RtlInitUnicodeString(&DeviceName,
1167 DPRINT("Creating device: %wZ\n", &DeviceName);
1169 /* Create the port device */
1170 Status = IoCreateDevice(DriverObject,
1171 PseudoDeviceExtension->Length,
1173 FILE_DEVICE_CONTROLLER,
1177 if (!NT_SUCCESS(Status))
1179 DbgPrint("IoCreateDevice call failed! (Status 0x%lX)\n", Status);
1183 DPRINT("Created device: %wZ\n", &DeviceName);
1185 /* Set the buffering strategy here... */
1186 PortDeviceObject->Flags |= DO_DIRECT_IO;
1187 PortDeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT;
1189 PortDeviceExtension = PortDeviceObject->DeviceExtension;
1191 /* Copy pseudo device extension into the real device extension */
1192 memcpy(PortDeviceExtension,
1193 PseudoDeviceExtension,
1194 PseudoDeviceExtension->Length);
1196 /* Copy access ranges */
1198 sizeof(ACCESS_RANGE) * PseudoDeviceExtension->PortConfig.NumberOfAccessRanges;
1199 PortDeviceExtension->PortConfig.AccessRanges = ExAllocatePool(NonPagedPool,
1201 memcpy(PortDeviceExtension->PortConfig.AccessRanges,
1202 PseudoDeviceExtension->PortConfig.AccessRanges,
1205 /* Copy device base list */
1206 if (IsListEmpty(&PseudoDeviceExtension->DeviceBaseListHead))
1208 InitializeListHead(&PortDeviceExtension->DeviceBaseListHead);
1212 PseudoDeviceExtension->DeviceBaseListHead.Flink =
1213 PortDeviceExtension->DeviceBaseListHead.Flink;
1214 PseudoDeviceExtension->DeviceBaseListHead.Blink =
1215 PortDeviceExtension->DeviceBaseListHead.Blink;
1216 PortDeviceExtension->DeviceBaseListHead.Blink->Flink =
1217 &PortDeviceExtension->DeviceBaseListHead;
1218 PortDeviceExtension->DeviceBaseListHead.Flink->Blink =
1219 &PortDeviceExtension->DeviceBaseListHead;
1222 PortDeviceExtension->DeviceObject = PortDeviceObject;
1223 PortDeviceExtension->PortNumber = PortNumber;
1225 /* Initialize the spin lock in the controller extension */
1226 KeInitializeSpinLock(&PortDeviceExtension->IrpLock);
1227 KeInitializeSpinLock(&PortDeviceExtension->SpinLock);
1229 /* Register an interrupt handler for this device */
1230 Status = IoConnectInterrupt(&PortDeviceExtension->Interrupt,
1232 PortDeviceExtension,
1233 &PortDeviceExtension->SpinLock,
1237 PortDeviceExtension->PortConfig.InterruptMode,
1241 if (!NT_SUCCESS(Status))
1243 DbgPrint("Could not Connect Interrupt %d\n",
1244 PortDeviceExtension->PortConfig.BusInterruptVector);
1248 /* Initialize the DPC object */
1249 IoInitializeDpcRequest(PortDeviceExtension->DeviceObject,
1252 /* Initialize the device timer */
1253 PortDeviceExtension->TimerState = IDETimerIdle;
1254 PortDeviceExtension->TimerCount = 0;
1255 IoInitializeTimer(PortDeviceExtension->DeviceObject,
1257 PortDeviceExtension);
1259 /* Initialize port capabilities */
1260 PortCapabilities = ExAllocatePool(NonPagedPool,
1261 sizeof(IO_SCSI_CAPABILITIES));
1262 PortDeviceExtension->PortCapabilities = PortCapabilities;
1263 PortCapabilities->Length = sizeof(IO_SCSI_CAPABILITIES);
1264 PortCapabilities->MaximumTransferLength =
1265 PortDeviceExtension->PortConfig.MaximumTransferLength;
1266 PortCapabilities->MaximumPhysicalPages =
1267 PortCapabilities->MaximumTransferLength / PAGE_SIZE;
1268 PortCapabilities->SupportedAsynchronousEvents = 0; /* FIXME */
1269 PortCapabilities->AlignmentMask =
1270 PortDeviceExtension->PortConfig.AlignmentMask;
1271 PortCapabilities->TaggedQueuing =
1272 PortDeviceExtension->PortConfig.TaggedQueuing;
1273 PortCapabilities->AdapterScansDown =
1274 PortDeviceExtension->PortConfig.AdapterScansDown;
1275 PortCapabilities->AdapterUsesPio = TRUE; /* FIXME */
1277 /* Initialize inquiry data */
1278 PortDeviceExtension->PortBusInfoSize = 0;
1279 PortDeviceExtension->PortBusInfo = NULL;
1281 DPRINT("DeviceExtension %p\n", PortDeviceExtension);
1282 ScsiPortInquire(PortDeviceExtension);
1285 /* FIXME: Copy more configuration data? */
1288 /* Create the dos device link */
1289 swprintf(DosNameBuffer,
1292 RtlInitUnicodeString(&DosDeviceName,
1295 IoCreateSymbolicLink(&DosDeviceName,
1298 *RealDeviceExtension = PortDeviceExtension;
1300 DPRINT("ScsiPortCreatePortDevice() done\n");
1302 return(STATUS_SUCCESS);
1307 ScsiPortInquire(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
1309 PSCSI_ADAPTER_BUS_INFO AdapterInfo;
1310 PSCSI_INQUIRY_DATA UnitInfo, PrevUnit;
1311 SCSI_REQUEST_BLOCK Srb;
1318 DPRINT("ScsiPortInquire() called\n");
1320 DeviceExtension->Initializing = TRUE;
1322 /* Copy inquiry data to the port device extension */
1323 AdapterInfo =(PSCSI_ADAPTER_BUS_INFO)ExAllocatePool(NonPagedPool, 4096);
1324 RtlZeroMemory(AdapterInfo, 4096);
1325 AdapterInfo->NumberOfBuses = DeviceExtension->PortConfig.NumberOfBuses;
1327 UnitInfo = (PSCSI_INQUIRY_DATA)
1328 ((PUCHAR)AdapterInfo + sizeof(SCSI_ADAPTER_BUS_INFO) +
1329 (sizeof(SCSI_BUS_DATA) * (AdapterInfo->NumberOfBuses - 1)));
1332 sizeof(SCSI_REQUEST_BLOCK));
1333 Srb.DataBuffer = ExAllocatePool(NonPagedPool, 256);
1334 Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
1335 Srb.DataTransferLength = 256;
1336 Srb.Cdb[0] = SCSIOP_INQUIRY;
1338 for (Bus = 0; Bus < AdapterInfo->NumberOfBuses; Bus++)
1342 AdapterInfo->BusData[Bus].InitiatorBusId =
1343 DeviceExtension->PortConfig.InitiatorBusId[Bus];
1344 AdapterInfo->BusData[Bus].InquiryDataOffset =
1345 (ULONG)((PUCHAR)UnitInfo - (PUCHAR)AdapterInfo);
1350 for (Target = 0; Target < DeviceExtension->PortConfig.MaximumNumberOfTargets; Target++)
1352 Srb.TargetId = Target;
1354 Srb.SrbStatus = SRB_STATUS_SUCCESS;
1356 Result = DeviceExtension->HwStartIo(&DeviceExtension->MiniPortDeviceExtension,
1358 DPRINT("Result: %s Srb.SrbStatus %lx\n", (Result)?"True":"False", Srb.SrbStatus);
1360 if (Result == TRUE && Srb.SrbStatus == SRB_STATUS_SUCCESS)
1362 UnitInfo->PathId = Bus;
1363 UnitInfo->TargetId = Target;
1365 UnitInfo->InquiryDataLength = INQUIRYDATABUFFERSIZE;
1366 memcpy(&UnitInfo->InquiryData,
1368 INQUIRYDATABUFFERSIZE);
1369 if (PrevUnit != NULL)
1370 PrevUnit->NextInquiryDataOffset = (ULONG)((PUCHAR)UnitInfo-(PUCHAR)AdapterInfo);
1371 PrevUnit = UnitInfo;
1372 UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)UnitInfo + sizeof(SCSI_INQUIRY_DATA)+INQUIRYDATABUFFERSIZE-1);
1376 DPRINT("UnitCount: %lu\n", UnitCount);
1377 AdapterInfo->BusData[Bus].NumberOfLogicalUnits = UnitCount;
1379 AdapterInfo->BusData[Bus].InquiryDataOffset = 0;
1381 DataSize = (ULONG)((PUCHAR)UnitInfo-(PUCHAR)AdapterInfo);
1383 ExFreePool(Srb.DataBuffer);
1385 DeviceExtension->Initializing = FALSE;
1387 /* copy inquiry data to the port driver's device extension */
1388 DeviceExtension->PortBusInfoSize = DataSize;
1389 DeviceExtension->PortBusInfo = ExAllocatePool(NonPagedPool,
1391 RtlCopyMemory(DeviceExtension->PortBusInfo,
1395 ExFreePool(AdapterInfo);
1397 DPRINT("ScsiPortInquire() done\n");
1401 static BOOLEAN STDCALL
1402 ScsiPortIsr(IN PKINTERRUPT Interrupt,
1403 IN PVOID ServiceContext)
1405 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1408 DPRINT("ScsiPortIsr() called!\n");
1410 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ServiceContext;
1412 Result = DeviceExtension->HwInterrupt(&DeviceExtension->MiniPortDeviceExtension);
1413 if (Result == FALSE)
1418 if (DeviceExtension->IrpFlags)
1420 IoRequestDpc(DeviceExtension->DeviceObject,
1421 DeviceExtension->CurrentIrp,
1429 // ScsiPortDpcForIsr
1436 // IN PDEVICE_OBJECT DpcDeviceObject
1438 // IN PVOID DpcContext
1441 ScsiPortDpcForIsr(IN PKDPC Dpc,
1442 IN PDEVICE_OBJECT DpcDeviceObject,
1444 IN PVOID DpcContext)
1446 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1447 PIO_STACK_LOCATION IrpStack;
1448 PSCSI_REQUEST_BLOCK Srb;
1451 DPRINT("ScsiPortDpcForIsr(Dpc %p DpcDeviceObject %p DpcIrp %p DpcContext %p)\n",
1452 Dpc, DpcDeviceObject, DpcIrp, DpcContext);
1454 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DpcContext;
1456 KeAcquireSpinLock(&DeviceExtension->IrpLock, &oldIrql);
1457 if (DeviceExtension->IrpFlags)
1459 IrpStack = IoGetCurrentIrpStackLocation(DeviceExtension->CurrentIrp);
1460 Srb = IrpStack->Parameters.Scsi.Srb;
1462 if (DeviceExtension->OriginalSrb != NULL)
1464 DPRINT("Got sense data!\n");
1466 DPRINT("Valid: %x\n", DeviceExtension->InternalSenseData.Valid);
1467 DPRINT("ErrorCode: %x\n", DeviceExtension->InternalSenseData.ErrorCode);
1468 DPRINT("SenseKey: %x\n", DeviceExtension->InternalSenseData.SenseKey);
1469 DPRINT("SenseCode: %x\n", DeviceExtension->InternalSenseData.AdditionalSenseCode);
1471 /* Copy sense data */
1472 if (DeviceExtension->OriginalSrb->SenseInfoBufferLength != 0)
1474 RtlCopyMemory(DeviceExtension->OriginalSrb->SenseInfoBuffer,
1475 &DeviceExtension->InternalSenseData,
1476 sizeof(SENSE_DATA));
1477 DeviceExtension->OriginalSrb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
1480 /* Clear current sense data */
1481 RtlZeroMemory(&DeviceExtension->InternalSenseData, sizeof(SENSE_DATA));
1483 IrpStack->Parameters.Scsi.Srb = DeviceExtension->OriginalSrb;
1484 DeviceExtension->OriginalSrb = NULL;
1486 else if ((SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS) &&
1487 (Srb->ScsiStatus == SCSISTAT_CHECK_CONDITION))
1489 DPRINT("SCSIOP_REQUEST_SENSE required!\n");
1491 DeviceExtension->OriginalSrb = Srb;
1492 IrpStack->Parameters.Scsi.Srb = ScsiPortInitSenseRequestSrb(DeviceExtension,
1494 KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
1495 if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
1496 ScsiPortStartPacket,
1499 DPRINT("Synchronization failed!\n");
1501 DpcIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
1502 DpcIrp->IoStatus.Information = 0;
1503 IoCompleteRequest(DpcIrp,
1505 IoStartNextPacket(DpcDeviceObject,
1512 DeviceExtension->CurrentIrp = NULL;
1515 // DpcIrp->IoStatus.Information = 0;
1516 // DpcIrp->IoStatus.Status = STATUS_SUCCESS;
1518 if (DeviceExtension->IrpFlags & IRP_FLAG_COMPLETE)
1520 DeviceExtension->IrpFlags &= ~IRP_FLAG_COMPLETE;
1521 IoCompleteRequest(DpcIrp, IO_NO_INCREMENT);
1524 if (DeviceExtension->IrpFlags & IRP_FLAG_NEXT)
1526 DeviceExtension->IrpFlags &= ~IRP_FLAG_NEXT;
1527 KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
1528 IoStartNextPacket(DpcDeviceObject, FALSE);
1532 KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
1537 KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
1539 DPRINT("ScsiPortDpcForIsr() done\n");
1545 // This function handles timeouts and other time delayed processing
1550 // IN PDEVICE_OBJECT DeviceObject Device object registered with timer
1551 // IN PVOID Context the Controller extension for the
1552 // controller the device is on
1555 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
1558 DPRINT1("ScsiPortIoTimer()\n");
1562 static PSCSI_REQUEST_BLOCK
1563 ScsiPortInitSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
1564 PSCSI_REQUEST_BLOCK OriginalSrb)
1566 PSCSI_REQUEST_BLOCK Srb;
1569 Srb = &DeviceExtension->InternalSrb;
1572 sizeof(SCSI_REQUEST_BLOCK));
1574 Srb->PathId = OriginalSrb->PathId;
1575 Srb->TargetId = OriginalSrb->TargetId;
1576 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1577 Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
1578 Srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
1580 Srb->TimeOutValue = 4;
1583 Srb->DataBuffer = &DeviceExtension->InternalSenseData;
1584 Srb->DataTransferLength = sizeof(SENSE_DATA);
1586 Cdb = (PCDB)Srb->Cdb;
1587 Cdb->CDB6INQUIRY.OperationCode = SCSIOP_REQUEST_SENSE;
1588 Cdb->CDB6INQUIRY.AllocationLength = sizeof(SENSE_DATA);
1595 ScsiPortFreeSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
1597 DeviceExtension->OriginalSrb = NULL;
1601 /**********************************************************************
1603 * ScsiPortBuildDeviceMap
1606 * Builds the registry device map of all device which are attached
1607 * to the given SCSI HBA port. The device map is located at:
1608 * \Registry\Machine\DeviceMap\Scsi
1618 * Name of registry driver service key.
1625 ScsiPortBuildDeviceMap(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
1626 PUNICODE_STRING RegistryPath)
1628 OBJECT_ATTRIBUTES ObjectAttributes;
1629 UNICODE_STRING KeyName;
1630 UNICODE_STRING ValueName;
1631 WCHAR NameBuffer[64];
1636 HANDLE ScsiInitiatorKey;
1637 HANDLE ScsiTargetKey;
1640 UCHAR CurrentTarget;
1641 PSCSI_ADAPTER_BUS_INFO AdapterInfo;
1642 PSCSI_INQUIRY_DATA UnitInfo;
1643 PINQUIRYDATA InquiryData;
1649 DPRINT("ScsiPortBuildDeviceMap() called\n");
1651 if (DeviceExtension == NULL || RegistryPath == NULL)
1653 DPRINT1("Invalid parameter\n");
1654 return(STATUS_INVALID_PARAMETER);
1657 /* Open or create the 'Scsi' subkey */
1658 RtlInitUnicodeStringFromLiteral(&KeyName,
1659 L"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
1660 InitializeObjectAttributes(&ObjectAttributes,
1662 OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
1665 Status = ZwCreateKey(&ScsiKey,
1670 REG_OPTION_VOLATILE,
1672 if (!NT_SUCCESS(Status))
1674 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
1678 /* Create new 'Scsi Port X' subkey */
1679 DPRINT("Scsi Port %lu\n",
1680 DeviceExtension->PortNumber);
1682 swprintf(NameBuffer,
1684 DeviceExtension->PortNumber);
1685 RtlInitUnicodeString(&KeyName,
1687 InitializeObjectAttributes(&ObjectAttributes,
1692 Status = ZwCreateKey(&ScsiPortKey,
1697 REG_OPTION_VOLATILE,
1700 if (!NT_SUCCESS(Status))
1702 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
1707 * Create port-specific values
1710 /* Set 'DMA Enabled' (REG_DWORD) value */
1711 UlongData = (ULONG)!DeviceExtension->PortCapabilities->AdapterUsesPio;
1712 DPRINT(" DMA Enabled = %s\n", (UlongData) ? "TRUE" : "FALSE");
1713 RtlInitUnicodeString(&ValueName,
1715 Status = ZwSetValueKey(ScsiPortKey,
1721 if (!NT_SUCCESS(Status))
1723 DPRINT("ZwSetValueKey('DMA Enabled') failed (Status %lx)\n", Status);
1724 ZwClose(ScsiPortKey);
1728 /* Set 'Driver' (REG_SZ) value */
1729 DriverName = wcsrchr(RegistryPath->Buffer, L'\\') + 1;
1730 DPRINT(" Driver = '%S'\n", DriverName);
1731 RtlInitUnicodeString(&ValueName,
1733 Status = ZwSetValueKey(ScsiPortKey,
1738 wcslen(DriverName) * sizeof(WCHAR));
1739 if (!NT_SUCCESS(Status))
1741 DPRINT("ZwSetValueKey('Driver') failed (Status %lx)\n", Status);
1742 ZwClose(ScsiPortKey);
1746 /* Set 'Interrupt' (REG_DWORD) value (NT4 only) */
1747 UlongData = (ULONG)DeviceExtension->PortConfig.BusInterruptLevel;
1748 DPRINT(" Interrupt = %lu\n", UlongData);
1749 RtlInitUnicodeString(&ValueName,
1751 Status = ZwSetValueKey(ScsiPortKey,
1757 if (!NT_SUCCESS(Status))
1759 DPRINT("ZwSetValueKey('Interrupt') failed (Status %lx)\n", Status);
1760 ZwClose(ScsiPortKey);
1764 /* Set 'IOAddress' (REG_DWORD) value (NT4 only) */
1765 UlongData = ScsiPortConvertPhysicalAddressToUlong(DeviceExtension->PortConfig.AccessRanges[0].RangeStart);
1766 DPRINT(" IOAddress = %lx\n", UlongData);
1767 RtlInitUnicodeString(&ValueName,
1769 Status = ZwSetValueKey(ScsiPortKey,
1775 if (!NT_SUCCESS(Status))
1777 DPRINT("ZwSetValueKey('IOAddress') failed (Status %lx)\n", Status);
1778 ZwClose(ScsiPortKey);
1782 /* Enumerate buses */
1783 for (BusNumber = 0; BusNumber < DeviceExtension->PortConfig.NumberOfBuses; BusNumber++)
1785 /* Create 'Scsi Bus X' key */
1786 DPRINT(" Scsi Bus %lu\n", BusNumber);
1787 swprintf(NameBuffer,
1790 RtlInitUnicodeString(&KeyName,
1792 InitializeObjectAttributes(&ObjectAttributes,
1797 Status = ZwCreateKey(&ScsiBusKey,
1802 REG_OPTION_VOLATILE,
1804 if (!NT_SUCCESS(Status))
1806 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
1807 ZwClose(ScsiPortKey);
1811 /* Create 'Initiator Id X' key */
1812 DPRINT(" Initiator Id %u\n",
1813 DeviceExtension->PortConfig.InitiatorBusId[BusNumber]);
1814 swprintf(NameBuffer,
1816 DeviceExtension->PortConfig.InitiatorBusId[BusNumber]);
1817 RtlInitUnicodeString(&KeyName,
1819 InitializeObjectAttributes(&ObjectAttributes,
1824 Status = ZwCreateKey(&ScsiInitiatorKey,
1829 REG_OPTION_VOLATILE,
1831 if (!NT_SUCCESS(Status))
1833 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
1834 ZwClose(ScsiBusKey);
1835 ZwClose(ScsiPortKey);
1839 /* FIXME: Are there any initiator values (??) */
1841 ZwClose(ScsiInitiatorKey);
1844 /* Enumerate targets */
1845 CurrentTarget = (UCHAR)-1;
1846 ScsiTargetKey = NULL;
1847 AdapterInfo = (PSCSI_ADAPTER_BUS_INFO)DeviceExtension->PortBusInfo;
1848 if (AdapterInfo->BusData[BusNumber].NumberOfLogicalUnits != 0)
1850 UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)AdapterInfo +
1851 AdapterInfo->BusData[BusNumber].InquiryDataOffset);
1853 while (AdapterInfo->BusData[BusNumber].InquiryDataOffset)
1855 if (UnitInfo->TargetId != CurrentTarget)
1857 /* Close old target key */
1858 if (ScsiTargetKey != NULL)
1860 ZwClose(ScsiTargetKey);
1861 ScsiTargetKey = NULL;
1864 /* Create 'Target Id X' key */
1865 DPRINT(" Target Id %u\n",
1866 UnitInfo->TargetId);
1867 swprintf(NameBuffer,
1869 UnitInfo->TargetId);
1870 RtlInitUnicodeString(&KeyName,
1872 InitializeObjectAttributes(&ObjectAttributes,
1877 Status = ZwCreateKey(&ScsiTargetKey,
1882 REG_OPTION_VOLATILE,
1884 if (!NT_SUCCESS(Status))
1886 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
1887 ZwClose(ScsiBusKey);
1888 ZwClose(ScsiPortKey);
1892 CurrentTarget = UnitInfo->TargetId;
1895 /* Create 'Logical Unit Id X' key */
1896 DPRINT(" Logical Unit Id %u\n",
1898 swprintf(NameBuffer,
1899 L"Logical Unit Id %u",
1901 RtlInitUnicodeString(&KeyName,
1903 InitializeObjectAttributes(&ObjectAttributes,
1908 Status = ZwCreateKey(&ScsiLunKey,
1913 REG_OPTION_VOLATILE,
1915 if (!NT_SUCCESS(Status))
1917 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
1918 ZwClose(ScsiTargetKey);
1919 ZwClose(ScsiBusKey);
1920 ZwClose(ScsiPortKey);
1924 /* Set values for logical unit */
1925 InquiryData = (PINQUIRYDATA)UnitInfo->InquiryData;
1927 /* Set 'Identifier' (REG_SZ) value */
1928 swprintf(NameBuffer,
1930 InquiryData->VendorId,
1931 InquiryData->ProductId,
1932 InquiryData->ProductRevisionLevel);
1933 DPRINT(" Identifier = '%S'\n",
1935 RtlInitUnicodeString(&ValueName,
1937 Status = ZwSetValueKey(ScsiLunKey,
1942 wcslen(NameBuffer) * sizeof(WCHAR));
1943 if (!NT_SUCCESS(Status))
1945 DPRINT("ZwSetValueKey('Identifier') failed (Status %lx)\n", Status);
1946 ZwClose(ScsiLunKey);
1947 ZwClose(ScsiTargetKey);
1948 ZwClose(ScsiBusKey);
1949 ZwClose(ScsiPortKey);
1953 /* Set 'Type' (REG_SZ) value */
1954 switch (InquiryData->DeviceType)
1957 TypeName = L"DiskPeripheral";
1960 TypeName = L"TapePeripheral";
1963 TypeName = L"PrinterPeripheral";
1966 TypeName = L"WormPeripheral";
1969 TypeName = L"CdRomPeripheral";
1972 TypeName = L"ScannerPeripheral";
1975 TypeName = L"OpticalDiskPeripheral";
1978 TypeName = L"MediumChangerPeripheral";
1981 TypeName = L"CommunicationPeripheral";
1984 TypeName = L"OtherPeripheral";
1987 DPRINT(" Type = '%S'\n", TypeName);
1988 RtlInitUnicodeString(&ValueName,
1990 Status = ZwSetValueKey(ScsiLunKey,
1995 wcslen(TypeName) * sizeof(WCHAR));
1996 if (!NT_SUCCESS(Status))
1998 DPRINT("ZwSetValueKey('Type') failed (Status %lx)\n", Status);
1999 ZwClose(ScsiLunKey);
2000 ZwClose(ScsiTargetKey);
2001 ZwClose(ScsiBusKey);
2002 ZwClose(ScsiPortKey);
2006 ZwClose(ScsiLunKey);
2008 if (UnitInfo->NextInquiryDataOffset == 0)
2011 UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)AdapterInfo +
2012 UnitInfo->NextInquiryDataOffset);
2015 /* Close old target key */
2016 if (ScsiTargetKey != NULL)
2018 ZwClose(ScsiTargetKey);
2019 ScsiTargetKey = NULL;
2023 ZwClose(ScsiBusKey);
2026 ZwClose(ScsiPortKey);
2028 DPRINT("ScsiPortBuildDeviceMap() done\n");