/* * PROJECT: ReactOS Storage Stack / SCSIPORT storage port library * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) * PURPOSE: Main and exported functions * COPYRIGHT: Eric Kohl (eric.kohl@reactos.org) * Aleksey Bragin (aleksey@reactos.org) * 2020 Victor Perevertkin (victor.perevertkin@reactos.org) */ /* INCLUDES *****************************************************************/ #include "scsiport.h" #define NDEBUG #include ULONG InternalDebugLevel = 0x00; #undef ScsiPortMoveMemory /* GLOBALS *******************************************************************/ static BOOLEAN SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT DeviceObject, IN struct _HW_INITIALIZATION_DATA *HwInitializationData, IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig, IN PUNICODE_STRING RegistryPath, IN ULONG BusNumber, IN OUT PPCI_SLOT_NUMBER NextSlotNumber); static NTSTATUS NTAPI ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); static VOID NTAPI ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject, PVOID Context); VOID NTAPI SpiMiniportTimerDpc(IN struct _KDPC *Dpc, IN PVOID DeviceObject, IN PVOID SystemArgument1, IN PVOID SystemArgument2); static NTSTATUS SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, PHW_INITIALIZATION_DATA HwInitData, PCONFIGURATION_INFO InternalConfigInfo, PPORT_CONFIGURATION_INFORMATION ConfigInfo, BOOLEAN FirstCall); NTSTATUS NTAPI SpQueryDeviceCallout(IN PVOID Context, IN PUNICODE_STRING PathName, IN INTERFACE_TYPE BusType, IN ULONG BusNumber, IN PKEY_VALUE_FULL_INFORMATION *BusInformation, IN CONFIGURATION_TYPE ControllerType, IN ULONG ControllerNumber, IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation, IN CONFIGURATION_TYPE PeripheralType, IN ULONG PeripheralNumber, IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation); static VOID SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, IN HANDLE Key, IN PPORT_CONFIGURATION_INFORMATION ConfigInfo, IN PCONFIGURATION_INFO InternalConfigInfo, IN PUCHAR Buffer); static VOID SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData, IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor, IN PPORT_CONFIGURATION_INFORMATION PortConfig); static PCM_RESOURCE_LIST SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, PPORT_CONFIGURATION_INFORMATION PortConfig); static NTSTATUS SpiAllocateCommonBuffer(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, ULONG NonCachedSize); NTHALAPI ULONG NTAPI HalGetBusData(BUS_DATA_TYPE, ULONG, ULONG, PVOID, ULONG); NTHALAPI ULONG NTAPI HalGetInterruptVector(INTERFACE_TYPE, ULONG, ULONG, ULONG, PKIRQL, PKAFFINITY); NTHALAPI NTSTATUS NTAPI HalAssignSlotResources(PUNICODE_STRING, PUNICODE_STRING, PDRIVER_OBJECT, PDEVICE_OBJECT, INTERFACE_TYPE, ULONG, ULONG, PCM_RESOURCE_LIST *); /* FUNCTIONS *****************************************************************/ /********************************************************************** * NAME EXPORTED * DriverEntry * * DESCRIPTION * This function initializes the driver. * * RUN LEVEL * PASSIVE_LEVEL * * ARGUMENTS * DriverObject * System allocated Driver Object for this driver. * * RegistryPath * Name of registry driver service key. * * RETURN VALUE * Status. */ NTSTATUS NTAPI DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) { return STATUS_SUCCESS; } VOID NTAPI ScsiPortUnload( _In_ PDRIVER_OBJECT DriverObject) { // no-op } NTSTATUS NTAPI ScsiPortDispatchPnp( PDEVICE_OBJECT DeviceObject, PIRP Irp) { if (((PSCSI_PORT_COMMON_EXTENSION)DeviceObject->DeviceExtension)->IsFDO) { return FdoDispatchPnp(DeviceObject, Irp); } else { return PdoDispatchPnp(DeviceObject, Irp); } } NTSTATUS NTAPI ScsiPortAddDevice( _In_ PDRIVER_OBJECT DriverObject, _In_ PDEVICE_OBJECT PhysicalDeviceObject) { DPRINT("AddDevice no-op DriverObj: %p, PDO: %p\n", DriverObject, PhysicalDeviceObject); return STATUS_SUCCESS; } /********************************************************************** * NAME EXPORTED * ScsiDebugPrint * * DESCRIPTION * Prints debugging messages. * * RUN LEVEL * PASSIVE_LEVEL * * ARGUMENTS * DebugPrintLevel * Debug level of the given message. * * DebugMessage * Pointer to printf()-compatible format string. * * ... Additional output data (see printf()). * * RETURN VALUE * None. * * @implemented */ VOID ScsiDebugPrint(IN ULONG DebugPrintLevel, IN PCHAR DebugMessage, ...) { char Buffer[256]; va_list ap; if (DebugPrintLevel > InternalDebugLevel) return; va_start(ap, DebugMessage); vsprintf(Buffer, DebugMessage, ap); va_end(ap); DbgPrint(Buffer); } /* An internal helper function for ScsiPortCompleteRequest */ VOID NTAPI SpiCompleteRequest(IN PVOID HwDeviceExtension, IN PSCSI_REQUEST_BLOCK_INFO SrbInfo, IN UCHAR SrbStatus) { PSCSI_REQUEST_BLOCK Srb; /* Get current SRB */ Srb = SrbInfo->Srb; /* Return if there is no SRB or it is not active */ if (!Srb || !(Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE)) return; /* Set status */ Srb->SrbStatus = SrbStatus; /* Set data transfered to 0 */ Srb->DataTransferLength = 0; /* Notify */ ScsiPortNotification(RequestComplete, HwDeviceExtension, Srb); } /* * @unimplemented */ VOID NTAPI ScsiPortCompleteRequest(IN PVOID HwDeviceExtension, IN UCHAR PathId, IN UCHAR TargetId, IN UCHAR Lun, IN UCHAR SrbStatus) { PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; PSCSI_PORT_LUN_EXTENSION LunExtension; PSCSI_REQUEST_BLOCK_INFO SrbInfo; PLIST_ENTRY ListEntry; DPRINT("ScsiPortCompleteRequest() called\n"); DeviceExtension = CONTAINING_RECORD(HwDeviceExtension, SCSI_PORT_DEVICE_EXTENSION, MiniPortDeviceExtension); /* Go through all buses */ for (UINT8 pathId = 0; pathId < DeviceExtension->NumberOfBuses; pathId++) { PSCSI_BUS_INFO bus = &DeviceExtension->Buses[pathId]; /* Go through all logical units */ for (PLIST_ENTRY lunEntry = bus->LunsListHead.Flink; lunEntry != &bus->LunsListHead; lunEntry = lunEntry->Flink) { LunExtension = CONTAINING_RECORD(lunEntry, SCSI_PORT_LUN_EXTENSION, LunEntry); /* Now match what caller asked with what we are at now */ if ((PathId == SP_UNTAGGED || PathId == LunExtension->PathId) && (TargetId == SP_UNTAGGED || TargetId == LunExtension->TargetId) && (Lun == SP_UNTAGGED || Lun == LunExtension->Lun)) { /* Yes, that's what caller asked for. Complete abort requests */ if (LunExtension->CompletedAbortRequests) { /* TODO: Save SrbStatus in this request */ DPRINT1("Completing abort request without setting SrbStatus!\n"); /* Issue a notification request */ ScsiPortNotification(RequestComplete, HwDeviceExtension, LunExtension->CompletedAbortRequests); } /* Complete the request using our helper */ SpiCompleteRequest(HwDeviceExtension, &LunExtension->SrbInfo, SrbStatus); /* Go through the queue and complete everything there too */ ListEntry = LunExtension->SrbInfo.Requests.Flink; while (ListEntry != &LunExtension->SrbInfo.Requests) { /* Get the actual SRB info entry */ SrbInfo = CONTAINING_RECORD(ListEntry, SCSI_REQUEST_BLOCK_INFO, Requests); /* Complete it */ SpiCompleteRequest(HwDeviceExtension, SrbInfo, SrbStatus); /* Advance to the next request in queue */ ListEntry = SrbInfo->Requests.Flink; } } } } } /* * @unimplemented */ VOID NTAPI ScsiPortFlushDma(IN PVOID HwDeviceExtension) { DPRINT("ScsiPortFlushDma()\n"); UNIMPLEMENTED; } /* * @implemented */ VOID NTAPI ScsiPortFreeDeviceBase(IN PVOID HwDeviceExtension, IN PVOID MappedAddress) { PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; PMAPPED_ADDRESS NextMa, LastMa; //DPRINT("ScsiPortFreeDeviceBase() called\n"); DeviceExtension = CONTAINING_RECORD(HwDeviceExtension, SCSI_PORT_DEVICE_EXTENSION, MiniPortDeviceExtension); /* Initialize our pointers */ NextMa = DeviceExtension->MappedAddressList; LastMa = NextMa; while (NextMa) { if (NextMa->MappedAddress == MappedAddress) { /* Unmap it first */ MmUnmapIoSpace(MappedAddress, NextMa->NumberOfBytes); /* Remove it from the list */ if (NextMa == DeviceExtension->MappedAddressList) { /* Remove the first entry */ DeviceExtension->MappedAddressList = NextMa->NextMappedAddress; } else { LastMa->NextMappedAddress = NextMa->NextMappedAddress; } /* Free the resources and quit */ ExFreePool(NextMa); return; } else { LastMa = NextMa; NextMa = NextMa->NextMappedAddress; } } } /* * @implemented */ ULONG NTAPI ScsiPortGetBusData(IN PVOID DeviceExtension, IN ULONG BusDataType, IN ULONG SystemIoBusNumber, IN ULONG SlotNumber, IN PVOID Buffer, IN ULONG Length) { DPRINT("ScsiPortGetBusData()\n"); if (Length) { /* If Length is non-zero, just forward the call to HalGetBusData() function */ return HalGetBusData(BusDataType, SystemIoBusNumber, SlotNumber, Buffer, Length); } /* We have a more complex case here */ UNIMPLEMENTED; return 0; } /* * @implemented */ ULONG NTAPI ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension, IN ULONG BusDataType, IN ULONG SystemIoBusNumber, IN ULONG SlotNumber, IN PVOID Buffer, IN ULONG Offset, IN ULONG Length) { DPRINT("ScsiPortSetBusDataByOffset()\n"); return HalSetBusDataByOffset(BusDataType, SystemIoBusNumber, SlotNumber, Buffer, Offset, Length); } /* * @implemented */ PVOID NTAPI ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension, IN INTERFACE_TYPE BusType, IN ULONG SystemIoBusNumber, IN SCSI_PHYSICAL_ADDRESS IoAddress, IN ULONG NumberOfBytes, IN BOOLEAN InIoSpace) { PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; PHYSICAL_ADDRESS TranslatedAddress; PMAPPED_ADDRESS DeviceBase; ULONG AddressSpace; PVOID MappedAddress; //DPRINT ("ScsiPortGetDeviceBase() called\n"); DeviceExtension = CONTAINING_RECORD(HwDeviceExtension, SCSI_PORT_DEVICE_EXTENSION, MiniPortDeviceExtension); AddressSpace = (ULONG)InIoSpace; if (HalTranslateBusAddress(BusType, SystemIoBusNumber, IoAddress, &AddressSpace, &TranslatedAddress) == FALSE) { return NULL; } /* i/o space */ if (AddressSpace != 0) return((PVOID)(ULONG_PTR)TranslatedAddress.QuadPart); MappedAddress = MmMapIoSpace(TranslatedAddress, NumberOfBytes, FALSE); DeviceBase = ExAllocatePoolWithTag(NonPagedPool, sizeof(MAPPED_ADDRESS), TAG_SCSIPORT); if (DeviceBase == NULL) return MappedAddress; DeviceBase->MappedAddress = MappedAddress; DeviceBase->NumberOfBytes = NumberOfBytes; DeviceBase->IoAddress = IoAddress; DeviceBase->BusNumber = SystemIoBusNumber; /* Link it to the Device Extension list */ DeviceBase->NextMappedAddress = DeviceExtension->MappedAddressList; DeviceExtension->MappedAddressList = DeviceBase; return MappedAddress; } /* * @unimplemented */ PVOID NTAPI ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension, IN UCHAR PathId, IN UCHAR TargetId, IN UCHAR Lun) { PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; PSCSI_PORT_LUN_EXTENSION LunExtension; DPRINT("ScsiPortGetLogicalUnit() called\n"); DeviceExtension = CONTAINING_RECORD(HwDeviceExtension, SCSI_PORT_DEVICE_EXTENSION, MiniPortDeviceExtension); /* Check the extension size */ if (!DeviceExtension->LunExtensionSize) { /* They didn't want one */ return NULL; } LunExtension = GetLunByPath(DeviceExtension, PathId, TargetId, Lun); /* Check that the logical unit exists */ if (!LunExtension) { /* Nope, return NULL */ return NULL; } /* Return the logical unit miniport extension */ return (LunExtension + 1); } /* * @implemented */ SCSI_PHYSICAL_ADDRESS NTAPI ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension, IN PSCSI_REQUEST_BLOCK Srb OPTIONAL, IN PVOID VirtualAddress, OUT ULONG *Length) { PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; SCSI_PHYSICAL_ADDRESS PhysicalAddress; SIZE_T BufferLength = 0; ULONG_PTR Offset; PSCSI_SG_ADDRESS SGList; PSCSI_REQUEST_BLOCK_INFO SrbInfo; DPRINT("ScsiPortGetPhysicalAddress(%p %p %p %p)\n", HwDeviceExtension, Srb, VirtualAddress, Length); DeviceExtension = CONTAINING_RECORD(HwDeviceExtension, SCSI_PORT_DEVICE_EXTENSION, MiniPortDeviceExtension); if (Srb == NULL || Srb->SenseInfoBuffer == VirtualAddress) { /* Simply look it up in the allocated common buffer */ Offset = (PUCHAR)VirtualAddress - (PUCHAR)DeviceExtension->SrbExtensionBuffer; BufferLength = DeviceExtension->CommonBufferLength - Offset; PhysicalAddress.QuadPart = DeviceExtension->PhysicalAddress.QuadPart + Offset; } else if (DeviceExtension->MapRegisters) { PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Srb->OriginalRequest); PSCSI_PORT_LUN_EXTENSION LunExtension = IoStack->DeviceObject->DeviceExtension; ASSERT(LunExtension && !LunExtension->Common.IsFDO); /* Scatter-gather list must be used */ SrbInfo = SpiGetSrbData(DeviceExtension, LunExtension, Srb->QueueTag); SGList = SrbInfo->ScatterGather; /* Find needed item in the SG list */ Offset = (PCHAR)VirtualAddress - (PCHAR)Srb->DataBuffer; while (Offset >= SGList->Length) { Offset -= SGList->Length; SGList++; } /* We're done, store length and physical address */ BufferLength = SGList->Length - Offset; PhysicalAddress.QuadPart = SGList->PhysicalAddress.QuadPart + Offset; } else { /* Nothing */ PhysicalAddress.QuadPart = (LONGLONG)(SP_UNINITIALIZED_VALUE); } *Length = (ULONG)BufferLength; return PhysicalAddress; } /* * @unimplemented */ PSCSI_REQUEST_BLOCK NTAPI ScsiPortGetSrb(IN PVOID DeviceExtension, IN UCHAR PathId, IN UCHAR TargetId, IN UCHAR Lun, IN LONG QueueTag) { DPRINT1("ScsiPortGetSrb() unimplemented\n"); UNIMPLEMENTED; return NULL; } /* * @implemented */ PVOID NTAPI ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension, IN PPORT_CONFIGURATION_INFORMATION ConfigInfo, IN ULONG NumberOfBytes) { PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; DEVICE_DESCRIPTION DeviceDescription; ULONG MapRegistersCount; NTSTATUS Status; DPRINT("ScsiPortGetUncachedExtension(%p %p %lu)\n", HwDeviceExtension, ConfigInfo, NumberOfBytes); DeviceExtension = CONTAINING_RECORD(HwDeviceExtension, SCSI_PORT_DEVICE_EXTENSION, MiniPortDeviceExtension); /* Check for allocated common DMA buffer */ if (DeviceExtension->SrbExtensionBuffer != NULL) { DPRINT1("The HBA has already got a common DMA buffer!\n"); return NULL; } /* Check for DMA adapter object */ if (DeviceExtension->AdapterObject == NULL) { /* Initialize DMA adapter description */ RtlZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION)); DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION; DeviceDescription.Master = ConfigInfo->Master; DeviceDescription.ScatterGather = ConfigInfo->ScatterGather; DeviceDescription.DemandMode = ConfigInfo->DemandMode; DeviceDescription.Dma32BitAddresses = ConfigInfo->Dma32BitAddresses; DeviceDescription.BusNumber = ConfigInfo->SystemIoBusNumber; DeviceDescription.DmaChannel = ConfigInfo->DmaChannel; DeviceDescription.InterfaceType = ConfigInfo->AdapterInterfaceType; DeviceDescription.DmaWidth = ConfigInfo->DmaWidth; DeviceDescription.DmaSpeed = ConfigInfo->DmaSpeed; DeviceDescription.MaximumLength = ConfigInfo->MaximumTransferLength; DeviceDescription.DmaPort = ConfigInfo->DmaPort; /* Get a DMA adapter object */ DeviceExtension->AdapterObject = HalGetAdapter(&DeviceDescription, &MapRegistersCount); /* Fail in case of error */ if (DeviceExtension->AdapterObject == NULL) { DPRINT1("HalGetAdapter() failed\n"); return NULL; } /* Set number of physical breaks */ if (ConfigInfo->NumberOfPhysicalBreaks != 0 && MapRegistersCount > ConfigInfo->NumberOfPhysicalBreaks) { DeviceExtension->PortCapabilities.MaximumPhysicalPages = ConfigInfo->NumberOfPhysicalBreaks; } else { DeviceExtension->PortCapabilities.MaximumPhysicalPages = MapRegistersCount; } } /* Update auto request sense feature */ DeviceExtension->SupportsAutoSense = ConfigInfo->AutoRequestSense; /* Update Srb extension size */ if (DeviceExtension->SrbExtensionSize != ConfigInfo->SrbExtensionSize) DeviceExtension->SrbExtensionSize = ConfigInfo->SrbExtensionSize; /* Update Srb extension alloc flag */ if (ConfigInfo->AutoRequestSense || DeviceExtension->SrbExtensionSize) DeviceExtension->NeedSrbExtensionAlloc = TRUE; /* Allocate a common DMA buffer */ Status = SpiAllocateCommonBuffer(DeviceExtension, NumberOfBytes); if (!NT_SUCCESS(Status)) { DPRINT1("SpiAllocateCommonBuffer() failed with Status = 0x%08X!\n", Status); return NULL; } return DeviceExtension->NonCachedExtension; } static NTSTATUS SpiAllocateCommonBuffer(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, ULONG NonCachedSize) { PVOID *SrbExtension, CommonBuffer; ULONG CommonBufferLength, BufSize; /* If size is 0, set it to 16 */ if (!DeviceExtension->SrbExtensionSize) DeviceExtension->SrbExtensionSize = 16; /* Calculate size */ BufSize = DeviceExtension->SrbExtensionSize; /* Add autosense data size if needed */ if (DeviceExtension->SupportsAutoSense) BufSize += sizeof(SENSE_DATA); /* Round it */ BufSize = (BufSize + sizeof(LONGLONG) - 1) & ~(sizeof(LONGLONG) - 1); /* Sum up into the total common buffer length, and round it to page size */ CommonBufferLength = ROUND_TO_PAGES(NonCachedSize + BufSize * DeviceExtension->RequestsNumber); /* Allocate it */ if (!DeviceExtension->AdapterObject) { /* From nonpaged pool if there is no DMA */ CommonBuffer = ExAllocatePoolWithTag(NonPagedPool, CommonBufferLength, TAG_SCSIPORT); } else { /* Perform a full request since we have a DMA adapter*/ CommonBuffer = HalAllocateCommonBuffer(DeviceExtension->AdapterObject, CommonBufferLength, &DeviceExtension->PhysicalAddress, FALSE ); } /* Fail in case of error */ if (!CommonBuffer) return STATUS_INSUFFICIENT_RESOURCES; /* Zero it */ RtlZeroMemory(CommonBuffer, CommonBufferLength); /* Store its size in Device Extension */ DeviceExtension->CommonBufferLength = CommonBufferLength; /* SrbExtension buffer is located at the beginning of the buffer */ DeviceExtension->SrbExtensionBuffer = CommonBuffer; /* Non-cached extension buffer is located at the end of the common buffer */ if (NonCachedSize) { CommonBufferLength -= NonCachedSize; DeviceExtension->NonCachedExtension = (PUCHAR)CommonBuffer + CommonBufferLength; } else { DeviceExtension->NonCachedExtension = NULL; } if (DeviceExtension->NeedSrbExtensionAlloc) { /* Look up how many SRB data structures we need */ DeviceExtension->SrbDataCount = CommonBufferLength / BufSize; /* Initialize the free SRB extensions list */ SrbExtension = (PVOID *)CommonBuffer; DeviceExtension->FreeSrbExtensions = SrbExtension; /* Fill the remaining pointers (if we have more than 1 SRB) */ while (CommonBufferLength >= 2 * BufSize) { *SrbExtension = (PVOID*)((PCHAR)SrbExtension + BufSize); SrbExtension = *SrbExtension; CommonBufferLength -= BufSize; } } return STATUS_SUCCESS; } /* * @implemented */ PVOID NTAPI ScsiPortGetVirtualAddress(IN PVOID HwDeviceExtension, IN SCSI_PHYSICAL_ADDRESS PhysicalAddress) { PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; ULONG Offset; DPRINT("ScsiPortGetVirtualAddress(%p %I64x)\n", HwDeviceExtension, PhysicalAddress.QuadPart); DeviceExtension = CONTAINING_RECORD(HwDeviceExtension, SCSI_PORT_DEVICE_EXTENSION, MiniPortDeviceExtension); if (DeviceExtension->PhysicalAddress.QuadPart > PhysicalAddress.QuadPart) return NULL; Offset = (ULONG)(PhysicalAddress.QuadPart - DeviceExtension->PhysicalAddress.QuadPart); if (Offset >= DeviceExtension->CommonBufferLength) return NULL; return (PVOID)((ULONG_PTR)DeviceExtension->SrbExtensionBuffer + Offset); } /********************************************************************** * NAME EXPORTED * ScsiPortInitialize * * DESCRIPTION * Initializes SCSI port driver specific data. * * RUN LEVEL * PASSIVE_LEVEL * * ARGUMENTS * Argument1 * Pointer to the miniport driver's driver object. * * Argument2 * Pointer to the miniport driver's registry path. * * HwInitializationData * Pointer to port driver specific configuration data. * * HwContext Miniport driver specific context. * * RETURN VALUE * Status. * * @implemented */ ULONG NTAPI ScsiPortInitialize( IN PVOID Argument1, IN PVOID Argument2, IN struct _HW_INITIALIZATION_DATA *HwInitializationData, IN PVOID HwContext) { PDRIVER_OBJECT DriverObject = (PDRIVER_OBJECT)Argument1; PUNICODE_STRING RegistryPath = (PUNICODE_STRING)Argument2; PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = NULL; PCONFIGURATION_INFORMATION SystemConfig; PPORT_CONFIGURATION_INFORMATION PortConfig; CONFIGURATION_INFO ConfigInfo; ULONG DeviceExtensionSize; ULONG PortConfigSize; BOOLEAN Again; BOOLEAN DeviceFound = FALSE; BOOLEAN FirstConfigCall = TRUE; ULONG Result; NTSTATUS Status; ULONG MaxBus; PCI_SLOT_NUMBER SlotNumber; PDEVICE_OBJECT PortDeviceObject; UNICODE_STRING DeviceName; PIO_SCSI_CAPABILITIES PortCapabilities; PCM_RESOURCE_LIST ResourceList; DPRINT ("ScsiPortInitialize() called!\n"); /* Check params for validity */ if ((HwInitializationData->HwInitialize == NULL) || (HwInitializationData->HwStartIo == NULL) || (HwInitializationData->HwInterrupt == NULL) || (HwInitializationData->HwFindAdapter == NULL) || (HwInitializationData->HwResetBus == NULL)) { return STATUS_REVISION_MISMATCH; } PSCSI_PORT_DRIVER_EXTENSION driverExtension; // ScsiPortInitialize may be called multiple times by the same driver driverExtension = IoGetDriverObjectExtension(DriverObject, HwInitializationData->HwInitialize); if (!driverExtension) { Status = IoAllocateDriverObjectExtension(DriverObject, HwInitializationData->HwInitialize, sizeof(SCSI_PORT_DRIVER_EXTENSION), (PVOID *)&driverExtension); if (!NT_SUCCESS(Status)) { DPRINT1("Failed to allocate the driver extension! Status 0x%x\n", Status); return Status; } } // set up the driver extension driverExtension->RegistryPath.Buffer = ExAllocatePoolWithTag(PagedPool, RegistryPath->MaximumLength, TAG_SCSIPORT); driverExtension->RegistryPath.MaximumLength = RegistryPath->MaximumLength; RtlCopyUnicodeString(&driverExtension->RegistryPath, RegistryPath); driverExtension->DriverObject = DriverObject; /* Set handlers */ DriverObject->DriverUnload = ScsiPortUnload; DriverObject->DriverStartIo = ScsiPortStartIo; DriverObject->DriverExtension->AddDevice = ScsiPortAddDevice; DriverObject->MajorFunction[IRP_MJ_CREATE] = ScsiPortCreateClose; DriverObject->MajorFunction[IRP_MJ_CLOSE] = ScsiPortCreateClose; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiPortDeviceControl; DriverObject->MajorFunction[IRP_MJ_SCSI] = ScsiPortDispatchScsi; DriverObject->MajorFunction[IRP_MJ_PNP] = ScsiPortDispatchPnp; DriverObject->MajorFunction[IRP_MJ_POWER] = ScsiPortDispatchPower; /* Obtain configuration information */ SystemConfig = IoGetConfigurationInformation(); /* Zero the internal configuration info structure */ RtlZeroMemory(&ConfigInfo, sizeof(CONFIGURATION_INFO)); /* Zero starting slot number */ SlotNumber.u.AsULONG = 0; /* Allocate space for access ranges */ if (HwInitializationData->NumberOfAccessRanges) { ConfigInfo.AccessRanges = ExAllocatePoolWithTag(PagedPool, HwInitializationData->NumberOfAccessRanges * sizeof(ACCESS_RANGE), TAG_SCSIPORT); /* Fail if failed */ if (ConfigInfo.AccessRanges == NULL) return STATUS_INSUFFICIENT_RESOURCES; } /* Open registry keys and fill the driverExtension */ SpiInitOpenKeys(&ConfigInfo, driverExtension); // FIXME: PnP miniports are not supported ASSERT(driverExtension->IsLegacyDriver); /* Last adapter number = not known */ ConfigInfo.LastAdapterNumber = SP_UNINITIALIZED_VALUE; /* Calculate sizes of DeviceExtension and PortConfig */ DeviceExtensionSize = sizeof(SCSI_PORT_DEVICE_EXTENSION) + HwInitializationData->DeviceExtensionSize; MaxBus = (HwInitializationData->AdapterInterfaceType == PCIBus) ? 8 : 1; DPRINT("MaxBus: %lu\n", MaxBus); while (TRUE) { WCHAR NameBuffer[27]; /* Create a unicode device name */ swprintf(NameBuffer, L"\\Device\\ScsiPort%lu", SystemConfig->ScsiPortCount); if (!RtlCreateUnicodeString(&DeviceName, NameBuffer)) { DPRINT1("Failed to allocate memory for device name!\n"); Status = STATUS_INSUFFICIENT_RESOURCES; PortDeviceObject = NULL; break; } DPRINT("Creating device: %wZ\n", &DeviceName); /* Create the port device */ Status = IoCreateDevice(DriverObject, DeviceExtensionSize, &DeviceName, FILE_DEVICE_CONTROLLER, FILE_DEVICE_SECURE_OPEN, FALSE, &PortDeviceObject); if (!NT_SUCCESS(Status)) { DPRINT1("IoCreateDevice call failed! (Status 0x%lX)\n", Status); PortDeviceObject = NULL; break; } DPRINT1("Created device: %wZ (%p)\n", &DeviceName, PortDeviceObject); /* Set the buffering strategy here... */ PortDeviceObject->Flags |= DO_DIRECT_IO; PortDeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT; /* FIXME: Is this really needed? */ /* Fill Device Extension */ DeviceExtension = PortDeviceObject->DeviceExtension; RtlZeroMemory(DeviceExtension, DeviceExtensionSize); DeviceExtension->Common.DeviceObject = PortDeviceObject; DeviceExtension->Common.IsFDO = TRUE; DeviceExtension->Length = DeviceExtensionSize; DeviceExtension->PortNumber = SystemConfig->ScsiPortCount; DeviceExtension->DeviceName = DeviceName; /* Driver's routines... */ DeviceExtension->HwInitialize = HwInitializationData->HwInitialize; DeviceExtension->HwStartIo = HwInitializationData->HwStartIo; DeviceExtension->HwInterrupt = HwInitializationData->HwInterrupt; DeviceExtension->HwResetBus = HwInitializationData->HwResetBus; DeviceExtension->HwDmaStarted = HwInitializationData->HwDmaStarted; /* Extensions sizes */ DeviceExtension->MiniPortExtensionSize = HwInitializationData->DeviceExtensionSize; DeviceExtension->LunExtensionSize = ALIGN_UP(HwInitializationData->SpecificLuExtensionSize, INT64); DeviceExtension->SrbExtensionSize = ALIGN_UP(HwInitializationData->SrbExtensionSize, INT64); /* Fill some numbers (bus count, lun count, etc) */ DeviceExtension->MaxLunCount = SCSI_MAXIMUM_LOGICAL_UNITS; DeviceExtension->RequestsNumber = 16; /* Initialize the spin lock in the controller extension */ KeInitializeSpinLock(&DeviceExtension->IrqLock); KeInitializeSpinLock(&DeviceExtension->SpinLock); /* Initialize the DPC object */ IoInitializeDpcRequest(PortDeviceObject, ScsiPortDpcForIsr); /* Initialize the device timer */ DeviceExtension->TimerCount = -1; IoInitializeTimer(PortDeviceObject, ScsiPortIoTimer, DeviceExtension); /* Initialize miniport timer */ KeInitializeTimer(&DeviceExtension->MiniportTimer); KeInitializeDpc(&DeviceExtension->MiniportTimerDpc, SpiMiniportTimerDpc, PortDeviceObject); CreatePortConfig: /* Allocate and initialize port configuration info */ PortConfigSize = sizeof(PORT_CONFIGURATION_INFORMATION) + HwInitializationData->NumberOfAccessRanges * sizeof(ACCESS_RANGE); PortConfigSize = ALIGN_UP(PortConfigSize, INT64); DeviceExtension->PortConfig = ExAllocatePoolWithTag(NonPagedPool, PortConfigSize, TAG_SCSIPORT); /* Fail if failed */ if (DeviceExtension->PortConfig == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; break; } Status = SpiCreatePortConfig(DeviceExtension, HwInitializationData, &ConfigInfo, DeviceExtension->PortConfig, FirstConfigCall); if (!NT_SUCCESS(Status)) { DPRINT("SpiCreatePortConfig() failed with Status 0x%08X\n", Status); break; } PortConfig = DeviceExtension->PortConfig; /* Copy extension sizes into the PortConfig */ PortConfig->SpecificLuExtensionSize = DeviceExtension->LunExtensionSize; PortConfig->SrbExtensionSize = DeviceExtension->SrbExtensionSize; /* Initialize Access ranges */ if (HwInitializationData->NumberOfAccessRanges != 0) { PortConfig->AccessRanges = ALIGN_UP_POINTER(PortConfig + 1, INT64); /* Copy the data */ RtlCopyMemory(PortConfig->AccessRanges, ConfigInfo.AccessRanges, HwInitializationData->NumberOfAccessRanges * sizeof(ACCESS_RANGE)); } /* Search for matching PCI device */ if ((HwInitializationData->AdapterInterfaceType == PCIBus) && (HwInitializationData->VendorIdLength > 0) && (HwInitializationData->VendorId != NULL) && (HwInitializationData->DeviceIdLength > 0) && (HwInitializationData->DeviceId != NULL)) { PortConfig->BusInterruptLevel = 0; /* Get PCI device data */ DPRINT( "VendorId '%.*s' DeviceId '%.*s'\n", HwInitializationData->VendorIdLength, HwInitializationData->VendorId, HwInitializationData->DeviceIdLength, HwInitializationData->DeviceId); if (!SpiGetPciConfigData( DriverObject, PortDeviceObject, HwInitializationData, PortConfig, RegistryPath, ConfigInfo.BusNumber, &SlotNumber)) { /* Continue to the next bus, nothing here */ ConfigInfo.BusNumber++; DeviceExtension->PortConfig = NULL; ExFreePool(PortConfig); Again = FALSE; goto CreatePortConfig; } if (!PortConfig->BusInterruptLevel) { /* Bypass this slot, because no interrupt was assigned */ DeviceExtension->PortConfig = NULL; ExFreePool(PortConfig); goto CreatePortConfig; } } else { DPRINT("Non-pci bus\n"); } /* Note: HwFindAdapter is called once for each bus */ Again = FALSE; DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig->SystemIoBusNumber); Result = (HwInitializationData->HwFindAdapter)( &DeviceExtension->MiniPortDeviceExtension, HwContext, 0, /* BusInformation */ ConfigInfo.Parameter, /* ArgumentString */ PortConfig, &Again); DPRINT("HwFindAdapter() Result: %lu Again: %s\n", Result, (Again) ? "True" : "False"); /* Free MapRegisterBase, it's not needed anymore */ if (DeviceExtension->MapRegisterBase != NULL) { ExFreePool(DeviceExtension->MapRegisterBase); DeviceExtension->MapRegisterBase = NULL; } /* If result is nothing good... */ if (Result != SP_RETURN_FOUND) { DPRINT("HwFindAdapter() Result: %lu\n", Result); if (Result == SP_RETURN_NOT_FOUND) { /* We can continue on the next bus */ ConfigInfo.BusNumber++; Again = FALSE; DeviceExtension->PortConfig = NULL; ExFreePool(PortConfig); goto CreatePortConfig; } /* Otherwise, break */ Status = STATUS_INTERNAL_ERROR; break; } DPRINT( "ScsiPortInitialize(): Found HBA! (%x), adapter Id %d\n", PortConfig->BusInterruptVector, PortConfig->InitiatorBusId[0]); /* If the SRB extension size was updated */ if (!DeviceExtension->NonCachedExtension && (PortConfig->SrbExtensionSize != DeviceExtension->SrbExtensionSize)) { /* Set it (rounding to LONGLONG again) */ DeviceExtension->SrbExtensionSize = ALIGN_UP(PortConfig->SrbExtensionSize, INT64); } /* The same with LUN extension size */ if (PortConfig->SpecificLuExtensionSize != DeviceExtension->LunExtensionSize) DeviceExtension->LunExtensionSize = PortConfig->SpecificLuExtensionSize; /* Construct a resource list */ ResourceList = SpiConfigToResource(DeviceExtension, PortConfig); PDEVICE_OBJECT LowerPDO = NULL; Status = IoReportDetectedDevice(DriverObject, HwInitializationData->AdapterInterfaceType, ConfigInfo.BusNumber, PortConfig->SlotNumber, ResourceList, NULL, TRUE, &LowerPDO); if (!NT_SUCCESS(Status)) { DPRINT1("IoReportDetectedDevice failed. Status: 0x%x\n", Status); __debugbreak(); break; } DeviceExtension->Common.LowerDevice = IoAttachDeviceToDeviceStack(PortDeviceObject, LowerPDO); ASSERT(DeviceExtension->Common.LowerDevice); PortDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; if (ResourceList) { ExFreePoolWithTag(ResourceList, TAG_SCSIPORT); } /* Copy all stuff which we ever need from PortConfig to the DeviceExtension */ if (PortConfig->MaximumNumberOfTargets > SCSI_MAXIMUM_TARGETS_PER_BUS) DeviceExtension->MaxTargedIds = SCSI_MAXIMUM_TARGETS_PER_BUS; else DeviceExtension->MaxTargedIds = PortConfig->MaximumNumberOfTargets; DeviceExtension->NumberOfBuses = PortConfig->NumberOfBuses; DeviceExtension->CachesData = PortConfig->CachesData; DeviceExtension->ReceiveEvent = PortConfig->ReceiveEvent; DeviceExtension->SupportsTaggedQueuing = PortConfig->TaggedQueuing; DeviceExtension->MultipleReqsPerLun = PortConfig->MultipleRequestPerLu; /* Initialize bus scanning information */ size_t BusConfigSize = DeviceExtension->NumberOfBuses * sizeof(*DeviceExtension->Buses); DeviceExtension->Buses = ExAllocatePoolZero(NonPagedPool, BusConfigSize, TAG_SCSIPORT); if (!DeviceExtension->Buses) { DPRINT1("Out of resources!\n"); Status = STATUS_INSUFFICIENT_RESOURCES; break; } // initialize bus data for (UINT8 pathId = 0; pathId < DeviceExtension->NumberOfBuses; pathId++) { DeviceExtension->Buses[pathId].BusIdentifier = DeviceExtension->PortConfig->InitiatorBusId[pathId]; InitializeListHead(&DeviceExtension->Buses[pathId].LunsListHead); } /* If something was disabled via registry - apply it */ if (ConfigInfo.DisableMultipleLun) DeviceExtension->MultipleReqsPerLun = PortConfig->MultipleRequestPerLu = FALSE; if (ConfigInfo.DisableTaggedQueueing) DeviceExtension->SupportsTaggedQueuing = PortConfig->MultipleRequestPerLu = FALSE; /* Check if we need to alloc SRB data */ if (DeviceExtension->SupportsTaggedQueuing || DeviceExtension->MultipleReqsPerLun) { DeviceExtension->NeedSrbDataAlloc = TRUE; } else { DeviceExtension->NeedSrbDataAlloc = FALSE; } /* Get a pointer to the port capabilities */ PortCapabilities = &DeviceExtension->PortCapabilities; /* Copy one field there */ DeviceExtension->MapBuffers = PortConfig->MapBuffers; PortCapabilities->AdapterUsesPio = PortConfig->MapBuffers; if (DeviceExtension->AdapterObject == NULL && (PortConfig->DmaChannel != SP_UNINITIALIZED_VALUE || PortConfig->Master)) { DPRINT1("DMA is not supported yet\n"); ASSERT(FALSE); } if (DeviceExtension->SrbExtensionBuffer == NULL && (DeviceExtension->SrbExtensionSize != 0 || PortConfig->AutoRequestSense)) { DeviceExtension->SupportsAutoSense = PortConfig->AutoRequestSense; DeviceExtension->NeedSrbExtensionAlloc = TRUE; /* Allocate common buffer */ Status = SpiAllocateCommonBuffer(DeviceExtension, 0); /* Check for failure */ if (!NT_SUCCESS(Status)) break; } /* Allocate SrbData, if needed */ if (DeviceExtension->NeedSrbDataAlloc) { ULONG Count; PSCSI_REQUEST_BLOCK_INFO SrbData; if (DeviceExtension->SrbDataCount != 0) Count = DeviceExtension->SrbDataCount; else Count = DeviceExtension->RequestsNumber * 2; /* Allocate the data */ SrbData = ExAllocatePoolWithTag( NonPagedPool, Count * sizeof(SCSI_REQUEST_BLOCK_INFO), TAG_SCSIPORT); if (SrbData == NULL) return STATUS_INSUFFICIENT_RESOURCES; RtlZeroMemory(SrbData, Count * sizeof(SCSI_REQUEST_BLOCK_INFO)); DeviceExtension->SrbInfo = SrbData; DeviceExtension->FreeSrbInfo = SrbData; DeviceExtension->SrbDataCount = Count; /* Link it to the list */ while (Count > 0) { SrbData->Requests.Flink = (PLIST_ENTRY)(SrbData + 1); SrbData++; Count--; } /* Mark the last entry of the list */ SrbData--; SrbData->Requests.Flink = NULL; } /* Initialize port capabilities */ PortCapabilities = &DeviceExtension->PortCapabilities; PortCapabilities->Length = sizeof(IO_SCSI_CAPABILITIES); PortCapabilities->MaximumTransferLength = PortConfig->MaximumTransferLength; if (PortConfig->ReceiveEvent) PortCapabilities->SupportedAsynchronousEvents |= SRBEV_SCSI_ASYNC_NOTIFICATION; PortCapabilities->TaggedQueuing = DeviceExtension->SupportsTaggedQueuing; PortCapabilities->AdapterScansDown = PortConfig->AdapterScansDown; if (PortConfig->AlignmentMask > PortDeviceObject->AlignmentRequirement) PortDeviceObject->AlignmentRequirement = PortConfig->AlignmentMask; PortCapabilities->AlignmentMask = PortDeviceObject->AlignmentRequirement; if (PortCapabilities->MaximumPhysicalPages == 0) { PortCapabilities->MaximumPhysicalPages = BYTES_TO_PAGES(PortCapabilities->MaximumTransferLength); /* Apply miniport's limits */ if (PortConfig->NumberOfPhysicalBreaks < PortCapabilities->MaximumPhysicalPages) { PortCapabilities->MaximumPhysicalPages = PortConfig->NumberOfPhysicalBreaks; } } FdoCallHWInitialize(DeviceExtension); Status = FdoStartAdapter(DeviceExtension); if (!NT_SUCCESS(Status)) { DPRINT1("Failed to start the legacy adapter. Status 0x%x\n", Status); break; } FdoScanAdapter(DeviceExtension); FirstConfigCall = FALSE; /* Increase adapter number and bus number respectively */ ConfigInfo.AdapterNumber++; if (!Again) ConfigInfo.BusNumber++; DPRINT("Bus: %lu MaxBus: %lu\n", ConfigInfo.BusNumber, MaxBus); DeviceFound = TRUE; } /* Clean up the mess */ if (!NT_SUCCESS(Status) && PortDeviceObject) { FdoRemoveAdapter(DeviceExtension); } /* Close registry keys */ if (ConfigInfo.ServiceKey != NULL) ZwClose(ConfigInfo.ServiceKey); if (ConfigInfo.DeviceKey != NULL) ZwClose(ConfigInfo.DeviceKey); if (ConfigInfo.BusKey != NULL) ZwClose(ConfigInfo.BusKey); if (ConfigInfo.AccessRanges != NULL) ExFreePool(ConfigInfo.AccessRanges); if (ConfigInfo.Parameter != NULL) ExFreePool(ConfigInfo.Parameter); DPRINT("ScsiPortInitialize() done, Status = 0x%08X, DeviceFound = %d!\n", Status, DeviceFound); return (DeviceFound == FALSE) ? Status : STATUS_SUCCESS; } /* * @unimplemented */ VOID NTAPI ScsiPortIoMapTransfer(IN PVOID HwDeviceExtension, IN PSCSI_REQUEST_BLOCK Srb, IN PVOID LogicalAddress, IN ULONG Length) { DPRINT1("ScsiPortIoMapTransfer()\n"); UNIMPLEMENTED; } /* * @unimplemented */ VOID NTAPI ScsiPortLogError(IN PVOID HwDeviceExtension, IN PSCSI_REQUEST_BLOCK Srb OPTIONAL, IN UCHAR PathId, IN UCHAR TargetId, IN UCHAR Lun, IN ULONG ErrorCode, IN ULONG UniqueId) { //PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; DPRINT1("ScsiPortLogError() called\n"); DPRINT1("PathId: 0x%02x TargetId: 0x%02x Lun: 0x%02x ErrorCode: 0x%08lx UniqueId: 0x%08lx\n", PathId, TargetId, Lun, ErrorCode, UniqueId); //DeviceExtension = CONTAINING_RECORD(HwDeviceExtension, SCSI_PORT_DEVICE_EXTENSION, MiniPortDeviceExtension); DPRINT("ScsiPortLogError() done\n"); } /* * @implemented */ VOID NTAPI ScsiPortMoveMemory(OUT PVOID Destination, IN PVOID Source, IN ULONG Length) { RtlMoveMemory(Destination, Source, Length); } /* * @implemented */ VOID ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType, IN PVOID HwDeviceExtension, ...) { PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; va_list ap; DPRINT("ScsiPortNotification() called\n"); DeviceExtension = CONTAINING_RECORD(HwDeviceExtension, SCSI_PORT_DEVICE_EXTENSION, MiniPortDeviceExtension); DPRINT("DeviceExtension %p\n", DeviceExtension); va_start(ap, HwDeviceExtension); switch (NotificationType) { case RequestComplete: { PSCSI_REQUEST_BLOCK Srb; PSCSI_REQUEST_BLOCK_INFO SrbData; Srb = (PSCSI_REQUEST_BLOCK)va_arg(ap, PSCSI_REQUEST_BLOCK); DPRINT("Notify: RequestComplete (Srb %p)\n", Srb); /* Make sure Srb is alright */ ASSERT(Srb->SrbStatus != SRB_STATUS_PENDING); ASSERT( Srb->Function != SRB_FUNCTION_EXECUTE_SCSI || Srb->SrbStatus != SRB_STATUS_SUCCESS || Srb->ScsiStatus == SCSISTAT_GOOD); if (!(Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE)) { /* It's been already completed */ va_end(ap); return; } /* It's not active anymore */ Srb->SrbFlags &= ~SRB_FLAGS_IS_ACTIVE; if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND) { /* TODO: Treat it specially */ ASSERT(FALSE); } else { PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Srb->OriginalRequest); PSCSI_PORT_LUN_EXTENSION LunExtension = IoStack->DeviceObject->DeviceExtension; ASSERT(LunExtension && !LunExtension->Common.IsFDO); /* Get the SRB data */ SrbData = SpiGetSrbData(DeviceExtension, LunExtension, Srb->QueueTag); /* Make sure there are no CompletedRequests and there is a Srb */ ASSERT(SrbData->CompletedRequests == NULL && SrbData->Srb != NULL); /* If it's a read/write request, make sure it has data inside it */ if ((Srb->SrbStatus == SRB_STATUS_SUCCESS) && ((Srb->Cdb[0] == SCSIOP_READ) || (Srb->Cdb[0] == SCSIOP_WRITE))) { ASSERT(Srb->DataTransferLength); } SrbData->CompletedRequests = DeviceExtension->InterruptData.CompletedRequests; DeviceExtension->InterruptData.CompletedRequests = SrbData; } } break; case NextRequest: DPRINT("Notify: NextRequest\n"); DeviceExtension->InterruptData.Flags |= SCSI_PORT_NEXT_REQUEST_READY; break; case NextLuRequest: { UCHAR PathId; UCHAR TargetId; UCHAR Lun; PSCSI_PORT_LUN_EXTENSION LunExtension; PathId = (UCHAR)va_arg(ap, int); TargetId = (UCHAR)va_arg(ap, int); Lun = (UCHAR)va_arg(ap, int); DPRINT( "Notify: NextLuRequest(PathId %u TargetId %u Lun %u)\n", PathId, TargetId, Lun); /* Mark it in the flags field */ DeviceExtension->InterruptData.Flags |= SCSI_PORT_NEXT_REQUEST_READY; /* Get the LUN extension */ LunExtension = GetLunByPath(DeviceExtension, PathId, TargetId, Lun); /* If returned LunExtension is NULL, break out */ if (!LunExtension) break; /* This request should not be processed if */ if ((LunExtension->ReadyLun) || (LunExtension->SrbInfo.Srb)) { /* Nothing to do here */ break; } /* Add this LUN to the list */ LunExtension->ReadyLun = DeviceExtension->InterruptData.ReadyLun; DeviceExtension->InterruptData.ReadyLun = LunExtension; } break; case ResetDetected: DPRINT("Notify: ResetDetected\n"); /* Add RESET flags */ DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET | SCSI_PORT_RESET_REPORTED; break; case CallDisableInterrupts: DPRINT1("UNIMPLEMENTED SCSI Notification called: CallDisableInterrupts!\n"); break; case CallEnableInterrupts: DPRINT1("UNIMPLEMENTED SCSI Notification called: CallEnableInterrupts!\n"); break; case RequestTimerCall: DPRINT("Notify: RequestTimerCall\n"); DeviceExtension->InterruptData.Flags |= SCSI_PORT_TIMER_NEEDED; DeviceExtension->InterruptData.HwScsiTimer = (PHW_TIMER)va_arg(ap, PHW_TIMER); DeviceExtension->InterruptData.MiniportTimerValue = (ULONG)va_arg(ap, ULONG); break; case BusChangeDetected: DPRINT1("UNIMPLEMENTED SCSI Notification called: BusChangeDetected!\n"); break; default: DPRINT1("Unsupported notification from WMI: %lu\n", NotificationType); break; } va_end(ap); /* Request a DPC after we're done with the interrupt */ DeviceExtension->InterruptData.Flags |= SCSI_PORT_NOTIFICATION_NEEDED; } /* * @implemented */ BOOLEAN NTAPI ScsiPortValidateRange(IN PVOID HwDeviceExtension, IN INTERFACE_TYPE BusType, IN ULONG SystemIoBusNumber, IN SCSI_PHYSICAL_ADDRESS IoAddress, IN ULONG NumberOfBytes, IN BOOLEAN InIoSpace) { DPRINT("ScsiPortValidateRange()\n"); return(TRUE); } /* INTERNAL FUNCTIONS ********************************************************/ static VOID SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData, IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor, IN PPORT_CONFIGURATION_INFORMATION PortConfig) { PACCESS_RANGE AccessRange; PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialData; ULONG RangeNumber; ULONG Index; ULONG Interrupt = 0; ULONG Dma = 0; RangeNumber = 0; /* Loop through all entries */ for (Index = 0; Index < ResourceDescriptor->PartialResourceList.Count; Index++) { PartialData = &ResourceDescriptor->PartialResourceList.PartialDescriptors[Index]; switch (PartialData->Type) { case CmResourceTypePort: /* Copy access ranges */ if (RangeNumber < HwInitializationData->NumberOfAccessRanges) { AccessRange = &((*(PortConfig->AccessRanges))[RangeNumber]); AccessRange->RangeStart = PartialData->u.Port.Start; AccessRange->RangeLength = PartialData->u.Port.Length; AccessRange->RangeInMemory = FALSE; RangeNumber++; } break; case CmResourceTypeMemory: /* Copy access ranges */ if (RangeNumber < HwInitializationData->NumberOfAccessRanges) { AccessRange = &((*(PortConfig->AccessRanges))[RangeNumber]); AccessRange->RangeStart = PartialData->u.Memory.Start; AccessRange->RangeLength = PartialData->u.Memory.Length; AccessRange->RangeInMemory = TRUE; RangeNumber++; } break; case CmResourceTypeInterrupt: if (Interrupt == 0) { /* Copy interrupt data */ PortConfig->BusInterruptLevel = PartialData->u.Interrupt.Level; PortConfig->BusInterruptVector = PartialData->u.Interrupt.Vector; /* Set interrupt mode accordingly to the resource */ if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LATCHED) { PortConfig->InterruptMode = Latched; } else if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE) { PortConfig->InterruptMode = LevelSensitive; } } else if (Interrupt == 1) { /* Copy interrupt data */ PortConfig->BusInterruptLevel2 = PartialData->u.Interrupt.Level; PortConfig->BusInterruptVector2 = PartialData->u.Interrupt.Vector; /* Set interrupt mode accordingly to the resource */ if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LATCHED) { PortConfig->InterruptMode2 = Latched; } else if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE) { PortConfig->InterruptMode2 = LevelSensitive; } } Interrupt++; break; case CmResourceTypeDma: if (Dma == 0) { PortConfig->DmaChannel = PartialData->u.Dma.Channel; PortConfig->DmaPort = PartialData->u.Dma.Port; if (PartialData->Flags & CM_RESOURCE_DMA_8) PortConfig->DmaWidth = Width8Bits; else if ((PartialData->Flags & CM_RESOURCE_DMA_16) || (PartialData->Flags & CM_RESOURCE_DMA_8_AND_16)) //??? PortConfig->DmaWidth = Width16Bits; else if (PartialData->Flags & CM_RESOURCE_DMA_32) PortConfig->DmaWidth = Width32Bits; } else if (Dma == 1) { PortConfig->DmaChannel2 = PartialData->u.Dma.Channel; PortConfig->DmaPort2 = PartialData->u.Dma.Port; if (PartialData->Flags & CM_RESOURCE_DMA_8) PortConfig->DmaWidth2 = Width8Bits; else if ((PartialData->Flags & CM_RESOURCE_DMA_16) || (PartialData->Flags & CM_RESOURCE_DMA_8_AND_16)) //??? PortConfig->DmaWidth2 = Width16Bits; else if (PartialData->Flags & CM_RESOURCE_DMA_32) PortConfig->DmaWidth2 = Width32Bits; } break; } } } static PCM_RESOURCE_LIST SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, PPORT_CONFIGURATION_INFORMATION PortConfig) { PCONFIGURATION_INFORMATION ConfigInfo; PCM_RESOURCE_LIST ResourceList; PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor; PACCESS_RANGE AccessRange; ULONG ListLength = 0, i, FullSize; ULONG Interrupt, Dma; /* Get current Atdisk usage from the system */ ConfigInfo = IoGetConfigurationInformation(); if (PortConfig->AtdiskPrimaryClaimed) ConfigInfo->AtDiskPrimaryAddressClaimed = TRUE; if (PortConfig->AtdiskSecondaryClaimed) ConfigInfo->AtDiskSecondaryAddressClaimed = TRUE; /* Do we use DMA? */ if (PortConfig->DmaChannel != SP_UNINITIALIZED_VALUE || PortConfig->DmaPort != SP_UNINITIALIZED_VALUE) { Dma = 1; if (PortConfig->DmaChannel2 != SP_UNINITIALIZED_VALUE || PortConfig->DmaPort2 != SP_UNINITIALIZED_VALUE) Dma++; } else { Dma = 0; } ListLength += Dma; /* How many interrupts to we have? */ Interrupt = DeviceExtension->InterruptCount; ListLength += Interrupt; /* How many access ranges do we use? */ AccessRange = &((*(PortConfig->AccessRanges))[0]); for (i = 0; i < PortConfig->NumberOfAccessRanges; i++) { if (AccessRange->RangeLength != 0) ListLength++; AccessRange++; } /* Allocate the resource list, since we know its size now */ FullSize = sizeof(CM_RESOURCE_LIST) + (ListLength - 1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR); ResourceList = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag(PagedPool, FullSize, TAG_SCSIPORT); if (!ResourceList) return NULL; /* Zero it */ RtlZeroMemory(ResourceList, FullSize); /* Initialize it */ ResourceList->Count = 1; ResourceList->List[0].InterfaceType = PortConfig->AdapterInterfaceType; ResourceList->List[0].BusNumber = PortConfig->SystemIoBusNumber; ResourceList->List[0].PartialResourceList.Count = ListLength; ResourceDescriptor = ResourceList->List[0].PartialResourceList.PartialDescriptors; /* Copy access ranges array over */ for (i = 0; i < PortConfig->NumberOfAccessRanges; i++) { AccessRange = &((*(PortConfig->AccessRanges))[i]); /* If the range is empty - skip it */ if (AccessRange->RangeLength == 0) continue; if (AccessRange->RangeInMemory) { ResourceDescriptor->Type = CmResourceTypeMemory; ResourceDescriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE; } else { ResourceDescriptor->Type = CmResourceTypePort; ResourceDescriptor->Flags = CM_RESOURCE_PORT_IO; } ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; ResourceDescriptor->u.Memory.Start = AccessRange->RangeStart; ResourceDescriptor->u.Memory.Length = AccessRange->RangeLength; ResourceDescriptor++; } /* If we use interrupt(s), copy them */ while (Interrupt) { ResourceDescriptor->Type = CmResourceTypeInterrupt; if (PortConfig->AdapterInterfaceType == MicroChannel || ((Interrupt == 2) ? PortConfig->InterruptMode2 : PortConfig->InterruptMode) == LevelSensitive) { ResourceDescriptor->ShareDisposition = CmResourceShareShared; ResourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; } else { ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; ResourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED; } ResourceDescriptor->u.Interrupt.Level = (Interrupt == 2) ? PortConfig->BusInterruptLevel2 : PortConfig->BusInterruptLevel; ResourceDescriptor->u.Interrupt.Vector = (Interrupt == 2) ? PortConfig->BusInterruptVector2 : PortConfig->BusInterruptVector; ResourceDescriptor->u.Interrupt.Affinity = 0; ResourceDescriptor++; Interrupt--; } /* Copy DMA data */ while (Dma) { ResourceDescriptor->Type = CmResourceTypeDma; ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; ResourceDescriptor->u.Dma.Channel = (Dma == 2) ? PortConfig->DmaChannel2 : PortConfig->DmaChannel; ResourceDescriptor->u.Dma.Port = (Dma == 2) ? PortConfig->DmaPort2 : PortConfig->DmaPort; ResourceDescriptor->Flags = 0; if (((Dma == 2) ? PortConfig->DmaWidth2 : PortConfig->DmaWidth) == Width8Bits) ResourceDescriptor->Flags |= CM_RESOURCE_DMA_8; else if (((Dma == 2) ? PortConfig->DmaWidth2 : PortConfig->DmaWidth) == Width16Bits) ResourceDescriptor->Flags |= CM_RESOURCE_DMA_16; else ResourceDescriptor->Flags |= CM_RESOURCE_DMA_32; if (((Dma == 2) ? PortConfig->DmaChannel2 : PortConfig->DmaChannel) == SP_UNINITIALIZED_VALUE) ResourceDescriptor->u.Dma.Channel = 0; if (((Dma == 2) ? PortConfig->DmaPort2 : PortConfig->DmaPort) == SP_UNINITIALIZED_VALUE) ResourceDescriptor->u.Dma.Port = 0; ResourceDescriptor++; Dma--; } return ResourceList; } static BOOLEAN SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT DeviceObject, IN struct _HW_INITIALIZATION_DATA *HwInitializationData, IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig, IN PUNICODE_STRING RegistryPath, IN ULONG BusNumber, IN OUT PPCI_SLOT_NUMBER NextSlotNumber) { PCI_COMMON_CONFIG PciConfig; PCI_SLOT_NUMBER SlotNumber; ULONG DataSize; ULONG DeviceNumber; ULONG FunctionNumber; CHAR VendorIdString[8]; CHAR DeviceIdString[8]; UNICODE_STRING UnicodeStr; PCM_RESOURCE_LIST ResourceList = NULL; NTSTATUS Status; DPRINT ("SpiGetPciConfiguration() called\n"); SlotNumber.u.AsULONG = 0; /* Loop through all devices */ for (DeviceNumber = NextSlotNumber->u.bits.DeviceNumber; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber++) { SlotNumber.u.bits.DeviceNumber = DeviceNumber; /* Loop through all functions */ for (FunctionNumber = NextSlotNumber->u.bits.FunctionNumber; FunctionNumber < PCI_MAX_FUNCTION; FunctionNumber++) { SlotNumber.u.bits.FunctionNumber = FunctionNumber; /* Get PCI config bytes */ DataSize = HalGetBusData(PCIConfiguration, BusNumber, SlotNumber.u.AsULONG, &PciConfig, sizeof(ULONG)); /* If result of HalGetBusData is 0, then the bus is wrong */ if (DataSize == 0) return FALSE; /* Check if result is PCI_INVALID_VENDORID or too small */ if ((DataSize < sizeof(ULONG)) || (PciConfig.VendorID == PCI_INVALID_VENDORID)) { /* Continue to try the next function */ continue; } sprintf (VendorIdString, "%04hx", PciConfig.VendorID); sprintf (DeviceIdString, "%04hx", PciConfig.DeviceID); if (_strnicmp(VendorIdString, HwInitializationData->VendorId, HwInitializationData->VendorIdLength) || _strnicmp(DeviceIdString, HwInitializationData->DeviceId, HwInitializationData->DeviceIdLength)) { /* It is not our device */ continue; } DPRINT("Found device 0x%04hx 0x%04hx at %1lu %2lu %1lu\n", PciConfig.VendorID, PciConfig.DeviceID, BusNumber, SlotNumber.u.bits.DeviceNumber, SlotNumber.u.bits.FunctionNumber); RtlInitUnicodeString(&UnicodeStr, L"ScsiAdapter"); Status = HalAssignSlotResources(RegistryPath, &UnicodeStr, DriverObject, DeviceObject, PCIBus, BusNumber, SlotNumber.u.AsULONG, &ResourceList); if (!NT_SUCCESS(Status)) break; /* Create configuration information */ SpiResourceToConfig(HwInitializationData, ResourceList->List, PortConfig); /* Free the resource list */ ExFreePool(ResourceList); /* Set dev & fn numbers */ NextSlotNumber->u.bits.DeviceNumber = DeviceNumber; NextSlotNumber->u.bits.FunctionNumber = FunctionNumber + 1; /* Save the slot number */ PortConfig->SlotNumber = SlotNumber.u.AsULONG; return TRUE; } NextSlotNumber->u.bits.FunctionNumber = 0; } NextSlotNumber->u.bits.DeviceNumber = 0; DPRINT ("No device found\n"); return FALSE; } /********************************************************************** * NAME INTERNAL * ScsiPortCreateClose * * DESCRIPTION * Answer requests for Create/Close calls: a null operation. * * RUN LEVEL * PASSIVE_LEVEL * * ARGUMENTS * DeviceObject * Pointer to a device object. * * Irp * Pointer to an IRP. * * RETURN VALUE * Status. */ static NTSTATUS NTAPI ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { DPRINT("ScsiPortCreateClose()\n"); Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS; } IO_ALLOCATION_ACTION NTAPI SpiAdapterControl(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID MapRegisterBase, PVOID Context) { PSCSI_REQUEST_BLOCK Srb; PSCSI_SG_ADDRESS ScatterGatherList; KIRQL CurrentIrql; PIO_STACK_LOCATION IrpStack; ULONG TotalLength = 0; PSCSI_REQUEST_BLOCK_INFO SrbInfo; PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; PUCHAR DataVA; BOOLEAN WriteToDevice; /* Get pointers to SrbInfo and DeviceExtension */ SrbInfo = (PSCSI_REQUEST_BLOCK_INFO)Context; DeviceExtension = DeviceObject->DeviceExtension; /* Get pointer to SRB */ IrpStack = IoGetCurrentIrpStackLocation(Irp); Srb = (PSCSI_REQUEST_BLOCK)IrpStack->Parameters.Others.Argument1; /* Depending on the map registers number, we allocate either from NonPagedPool, or from our static list */ if (SrbInfo->NumberOfMapRegisters > MAX_SG_LIST) { SrbInfo->ScatterGather = ExAllocatePoolWithTag( NonPagedPool, SrbInfo->NumberOfMapRegisters * sizeof(SCSI_SG_ADDRESS), TAG_SCSIPORT); if (SrbInfo->ScatterGather == NULL) ASSERT(FALSE); Srb->SrbFlags |= SRB_FLAGS_SGLIST_FROM_POOL; } else { SrbInfo->ScatterGather = SrbInfo->ScatterGatherList; } /* Use chosen SG list source */ ScatterGatherList = SrbInfo->ScatterGather; /* Save map registers base */ SrbInfo->BaseOfMapRegister = MapRegisterBase; /* Determine WriteToDevice flag */ WriteToDevice = Srb->SrbFlags & SRB_FLAGS_DATA_OUT ? TRUE : FALSE; /* Get virtual address of the data buffer */ DataVA = (PUCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress) + ((PCHAR)Srb->DataBuffer - SrbInfo->DataOffset); /* Build the actual SG list */ while (TotalLength < Srb->DataTransferLength) { if (!ScatterGatherList) break; ScatterGatherList->Length = Srb->DataTransferLength - TotalLength; ScatterGatherList->PhysicalAddress = IoMapTransfer(DeviceExtension->AdapterObject, Irp->MdlAddress, MapRegisterBase, DataVA + TotalLength, &ScatterGatherList->Length, WriteToDevice); TotalLength += ScatterGatherList->Length; ScatterGatherList++; } /* Schedule an active request */ InterlockedIncrement(&DeviceExtension->ActiveRequestCounter ); KeAcquireSpinLock(&DeviceExtension->SpinLock, &CurrentIrql); KeSynchronizeExecution(DeviceExtension->Interrupt[0], ScsiPortStartPacket, DeviceObject); KeReleaseSpinLock(&DeviceExtension->SpinLock, CurrentIrql); return DeallocateObjectKeepRegisters; } BOOLEAN NTAPI ScsiPortIsr( _In_ PKINTERRUPT Interrupt, _In_ PVOID ServiceContext) { PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; DPRINT("ScsiPortIsr() called!\n"); DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ServiceContext; /* If interrupts are disabled - we don't expect any */ if (DeviceExtension->InterruptData.Flags & SCSI_PORT_DISABLE_INTERRUPTS) return FALSE; /* Call miniport's HwInterrupt routine */ if (DeviceExtension->HwInterrupt(&DeviceExtension->MiniPortDeviceExtension) == FALSE) { /* This interrupt doesn't belong to us */ return FALSE; } /* If flag of notification is set - queue a DPC */ if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED) { IoRequestDpc(DeviceExtension->Common.DeviceObject, DeviceExtension->CurrentIrp, DeviceExtension); } return TRUE; } BOOLEAN NTAPI SpiProcessTimeout(PVOID ServiceContext) { PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)ServiceContext; PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; ULONG Bus; DPRINT("SpiProcessTimeout() entered\n"); DeviceExtension->TimerCount = -1; if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET) { DeviceExtension->InterruptData.Flags &= ~SCSI_PORT_RESET; if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET_REQUEST) { DeviceExtension->InterruptData.Flags &= ~SCSI_PORT_RESET_REQUEST; ScsiPortStartPacket(ServiceContext); } return FALSE; } else { DPRINT("Resetting the bus\n"); for (Bus = 0; Bus < DeviceExtension->NumberOfBuses; Bus++) { DeviceExtension->HwResetBus(DeviceExtension->MiniPortDeviceExtension, Bus); /* Reset flags and set reset timeout to 4 seconds */ DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET; DeviceExtension->TimerCount = 4; } /* If miniport requested - request a dpc for it */ if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED) IoRequestDpc(DeviceExtension->Common.DeviceObject, NULL, NULL); } return TRUE; } BOOLEAN NTAPI SpiResetBus(PVOID ServiceContext) { PRESETBUS_PARAMS ResetParams = (PRESETBUS_PARAMS)ServiceContext; PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; /* Perform the bus reset */ DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ResetParams->DeviceExtension; DeviceExtension->HwResetBus(DeviceExtension->MiniPortDeviceExtension, ResetParams->PathId); /* Set flags and start the timer */ DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET; DeviceExtension->TimerCount = 4; /* If miniport requested - give him a DPC */ if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED) IoRequestDpc(DeviceExtension->Common.DeviceObject, NULL, NULL); return TRUE; } // ScsiPortIoTimer // DESCRIPTION: // This function handles timeouts and other time delayed processing // // RUN LEVEL: // // ARGUMENTS: // IN PDEVICE_OBJECT DeviceObject Device object registered with timer // IN PVOID Context the Controller extension for the // controller the device is on // static VOID NTAPI ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject, PVOID Context) { PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; PSCSI_PORT_LUN_EXTENSION LunExtension; PIRP Irp; DPRINT("ScsiPortIoTimer()\n"); DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension; /* Protect with the spinlock */ KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock); /* Check timeouts */ if (DeviceExtension->TimerCount > 0) { /* Decrease the timeout counter */ DeviceExtension->TimerCount--; if (DeviceExtension->TimerCount == 0) { /* Timeout, process it */ if (KeSynchronizeExecution(DeviceExtension->Interrupt[0], SpiProcessTimeout, DeviceExtension->Common.DeviceObject)) { DPRINT("Error happened during processing timeout, but nothing critical\n"); } } KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); /* We should exit now, since timeout is processed */ return; } /* Per-Lun scanning of timeouts is needed... */ for (UINT8 pathId = 0; pathId < DeviceExtension->NumberOfBuses; pathId++) { PSCSI_BUS_INFO bus = &DeviceExtension->Buses[pathId]; for (PLIST_ENTRY lunEntry = bus->LunsListHead.Flink; lunEntry != &bus->LunsListHead; lunEntry = lunEntry->Flink) { LunExtension = CONTAINING_RECORD(lunEntry, SCSI_PORT_LUN_EXTENSION, LunEntry); if (LunExtension->Flags & LUNEX_BUSY) { if (!(LunExtension->Flags & (LUNEX_NEED_REQUEST_SENSE | LUNEX_FROZEN_QUEUE))) { DPRINT("Retrying busy request\n"); /* Clear flags, and retry busy request */ LunExtension->Flags &= ~(LUNEX_BUSY | LUNEX_FULL_QUEUE); Irp = LunExtension->BusyRequest; /* Clearing busy request */ LunExtension->BusyRequest = NULL; KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); IoStartPacket(DeviceObject, Irp, (PULONG)NULL, NULL); KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock); } } else if (LunExtension->RequestTimeout == 0) { RESETBUS_PARAMS ResetParams; LunExtension->RequestTimeout = -1; DPRINT("Request timed out, resetting bus\n"); /* Pass params to the bus reset routine */ ResetParams.PathId = LunExtension->PathId; ResetParams.DeviceExtension = DeviceExtension; if (!KeSynchronizeExecution(DeviceExtension->Interrupt[0], SpiResetBus, &ResetParams)) { DPRINT1("Reset failed\n"); } } else if (LunExtension->RequestTimeout > 0) { /* Decrement the timeout counter */ LunExtension->RequestTimeout--; } } } /* Release the spinlock */ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); } VOID NTAPI SpiMiniportTimerDpc(IN struct _KDPC *Dpc, IN PVOID DeviceObject, IN PVOID SystemArgument1, IN PVOID SystemArgument2) { PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; DPRINT("Miniport timer DPC\n"); DeviceExtension = ((PDEVICE_OBJECT)DeviceObject)->DeviceExtension; /* Acquire the spinlock */ KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock); /* Call the timer routine */ if (DeviceExtension->HwScsiTimer != NULL) { DeviceExtension->HwScsiTimer(&DeviceExtension->MiniPortDeviceExtension); } /* Release the spinlock */ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED) { ScsiPortDpcForIsr(NULL, DeviceExtension->Common.DeviceObject, NULL, NULL); } } static NTSTATUS SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, PHW_INITIALIZATION_DATA HwInitData, PCONFIGURATION_INFO InternalConfigInfo, PPORT_CONFIGURATION_INFORMATION ConfigInfo, BOOLEAN ZeroStruct) { UNICODE_STRING UnicodeString; OBJECT_ATTRIBUTES ObjectAttributes; PCONFIGURATION_INFORMATION DdkConfigInformation; HANDLE RootKey, Key; BOOLEAN Found; WCHAR DeviceBuffer[16]; WCHAR StrBuffer[512]; ULONG Bus; NTSTATUS Status; /* Zero out the struct if told so */ if (ZeroStruct) { /* First zero the portconfig */ RtlZeroMemory(ConfigInfo, sizeof(PORT_CONFIGURATION_INFORMATION)); /* Then access ranges */ RtlZeroMemory(InternalConfigInfo->AccessRanges, HwInitData->NumberOfAccessRanges * sizeof(ACCESS_RANGE)); /* Initialize the struct */ ConfigInfo->Length = sizeof(PORT_CONFIGURATION_INFORMATION); ConfigInfo->AdapterInterfaceType = HwInitData->AdapterInterfaceType; ConfigInfo->InterruptMode = Latched; ConfigInfo->DmaChannel = SP_UNINITIALIZED_VALUE; ConfigInfo->DmaPort = SP_UNINITIALIZED_VALUE; ConfigInfo->DmaChannel2 = SP_UNINITIALIZED_VALUE; ConfigInfo->DmaPort2 = SP_UNINITIALIZED_VALUE; ConfigInfo->MaximumTransferLength = SP_UNINITIALIZED_VALUE; ConfigInfo->NumberOfAccessRanges = HwInitData->NumberOfAccessRanges; ConfigInfo->MaximumNumberOfTargets = 8; /* Store parameters */ ConfigInfo->NeedPhysicalAddresses = HwInitData->NeedPhysicalAddresses; ConfigInfo->MapBuffers = HwInitData->MapBuffers; ConfigInfo->AutoRequestSense = HwInitData->AutoRequestSense; ConfigInfo->ReceiveEvent = HwInitData->ReceiveEvent; ConfigInfo->TaggedQueuing = HwInitData->TaggedQueuing; ConfigInfo->MultipleRequestPerLu = HwInitData->MultipleRequestPerLu; /* Get the disk usage */ DdkConfigInformation = IoGetConfigurationInformation(); ConfigInfo->AtdiskPrimaryClaimed = DdkConfigInformation->AtDiskPrimaryAddressClaimed; ConfigInfo->AtdiskSecondaryClaimed = DdkConfigInformation->AtDiskSecondaryAddressClaimed; /* Initiator bus id is not set */ for (Bus = 0; Bus < 8; Bus++) ConfigInfo->InitiatorBusId[Bus] = (CCHAR)SP_UNINITIALIZED_VALUE; } ConfigInfo->NumberOfPhysicalBreaks = 17; /* Clear this information */ InternalConfigInfo->DisableTaggedQueueing = FALSE; InternalConfigInfo->DisableMultipleLun = FALSE; /* Store Bus Number */ ConfigInfo->SystemIoBusNumber = InternalConfigInfo->BusNumber; TryNextAd: if (ConfigInfo->AdapterInterfaceType == Internal) { /* Open registry key for HW database */ InitializeObjectAttributes(&ObjectAttributes, DeviceExtension->Common.DeviceObject->DriverObject->HardwareDatabase, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); Status = ZwOpenKey(&RootKey, KEY_READ, &ObjectAttributes); if (NT_SUCCESS(Status)) { /* Create name for it */ swprintf(StrBuffer, L"ScsiAdapter\\%lu", InternalConfigInfo->AdapterNumber); RtlInitUnicodeString(&UnicodeString, StrBuffer); /* Open device key */ InitializeObjectAttributes(&ObjectAttributes, &UnicodeString, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, RootKey, NULL); Status = ZwOpenKey(&Key, KEY_READ, &ObjectAttributes); ZwClose(RootKey); if (NT_SUCCESS(Status)) { if (InternalConfigInfo->LastAdapterNumber != InternalConfigInfo->AdapterNumber) { DPRINT("Hardware info found at %S\n", StrBuffer); /* Parse it */ SpiParseDeviceInfo(DeviceExtension, Key, ConfigInfo, InternalConfigInfo, (PUCHAR)StrBuffer); InternalConfigInfo->BusNumber = 0; } else { /* Try the next adapter */ InternalConfigInfo->AdapterNumber++; goto TryNextAd; } } else { /* Info was not found, exit */ DPRINT1("ZwOpenKey() failed with Status=0x%08X\n", Status); return STATUS_DEVICE_DOES_NOT_EXIST; } } else { DPRINT1("ZwOpenKey() failed with Status=0x%08X\n", Status); } } /* Look at device params */ Key = NULL; if (InternalConfigInfo->Parameter) { ExFreePool(InternalConfigInfo->Parameter); InternalConfigInfo->Parameter = NULL; } if (InternalConfigInfo->ServiceKey != NULL) { swprintf(DeviceBuffer, L"Device%lu", InternalConfigInfo->AdapterNumber); RtlInitUnicodeString(&UnicodeString, DeviceBuffer); /* Open the service key */ InitializeObjectAttributes(&ObjectAttributes, &UnicodeString, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, InternalConfigInfo->ServiceKey, NULL); Status = ZwOpenKey(&Key, KEY_READ, &ObjectAttributes); } /* Parse device key */ if (InternalConfigInfo->DeviceKey != NULL) { SpiParseDeviceInfo(DeviceExtension, InternalConfigInfo->DeviceKey, ConfigInfo, InternalConfigInfo, (PUCHAR)StrBuffer); } /* Then parse hw info */ if (Key != NULL) { if (InternalConfigInfo->LastAdapterNumber != InternalConfigInfo->AdapterNumber) { SpiParseDeviceInfo(DeviceExtension, Key, ConfigInfo, InternalConfigInfo, (PUCHAR)StrBuffer); /* Close the key */ ZwClose(Key); } else { /* Adapter not found, go try the next one */ InternalConfigInfo->AdapterNumber++; /* Close the key */ ZwClose(Key); goto TryNextAd; } } /* Update the last adapter number */ InternalConfigInfo->LastAdapterNumber = InternalConfigInfo->AdapterNumber; /* Do we have this kind of bus at all? */ Found = FALSE; Status = IoQueryDeviceDescription(&HwInitData->AdapterInterfaceType, &InternalConfigInfo->BusNumber, NULL, NULL, NULL, NULL, SpQueryDeviceCallout, &Found); /* This bus was not found */ if (!Found) { INTERFACE_TYPE InterfaceType = Eisa; /* Check for EISA */ if (HwInitData->AdapterInterfaceType == Isa) { Status = IoQueryDeviceDescription(&InterfaceType, &InternalConfigInfo->BusNumber, NULL, NULL, NULL, NULL, SpQueryDeviceCallout, &Found); /* Return respectively */ if (Found) return STATUS_SUCCESS; else return STATUS_DEVICE_DOES_NOT_EXIST; } else { return STATUS_DEVICE_DOES_NOT_EXIST; } } else { return STATUS_SUCCESS; } } static VOID SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, IN HANDLE Key, IN PPORT_CONFIGURATION_INFORMATION ConfigInfo, IN PCONFIGURATION_INFO InternalConfigInfo, IN PUCHAR Buffer) { PKEY_VALUE_FULL_INFORMATION KeyValueInformation; PCM_FULL_RESOURCE_DESCRIPTOR FullResource; PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor; PCM_SCSI_DEVICE_DATA ScsiDeviceData; ULONG Length, Count, Dma = 0, Interrupt = 0; ULONG Index = 0, RangeCount = 0; UNICODE_STRING UnicodeString; ANSI_STRING AnsiString; NTSTATUS Status = STATUS_SUCCESS; KeyValueInformation = (PKEY_VALUE_FULL_INFORMATION) Buffer; /* Loop through all values in the device node */ while(TRUE) { Status = ZwEnumerateValueKey(Key, Index, KeyValueFullInformation, Buffer, 512, &Length); if (!NT_SUCCESS(Status)) return; Index++; /* Length for DWORD is ok? */ if (KeyValueInformation->Type == REG_DWORD && KeyValueInformation->DataLength != sizeof(ULONG)) { continue; } /* Get MaximumLogicalUnit */ if (_wcsnicmp(KeyValueInformation->Name, L"MaximumLogicalUnit", KeyValueInformation->NameLength/2) == 0) { if (KeyValueInformation->Type != REG_DWORD) { DPRINT("Bad data type for MaximumLogicalUnit\n"); continue; } DeviceExtension->MaxLunCount = *((PUCHAR) (Buffer + KeyValueInformation->DataOffset)); /* Check / reset if needed */ if (DeviceExtension->MaxLunCount > SCSI_MAXIMUM_LOGICAL_UNITS) DeviceExtension->MaxLunCount = SCSI_MAXIMUM_LOGICAL_UNITS; DPRINT("MaximumLogicalUnit = %d\n", DeviceExtension->MaxLunCount); } /* Get InitiatorTargetId */ if (_wcsnicmp(KeyValueInformation->Name, L"InitiatorTargetId", KeyValueInformation->NameLength / 2) == 0) { if (KeyValueInformation->Type != REG_DWORD) { DPRINT("Bad data type for InitiatorTargetId\n"); continue; } ConfigInfo->InitiatorBusId[0] = *((PUCHAR) (Buffer + KeyValueInformation->DataOffset)); /* Check / reset if needed */ if (ConfigInfo->InitiatorBusId[0] > ConfigInfo->MaximumNumberOfTargets - 1) ConfigInfo->InitiatorBusId[0] = (CCHAR)-1; DPRINT("InitiatorTargetId = %d\n", ConfigInfo->InitiatorBusId[0]); } /* Get ScsiDebug */ if (_wcsnicmp(KeyValueInformation->Name, L"ScsiDebug", KeyValueInformation->NameLength/2) == 0) { DPRINT("ScsiDebug key not supported\n"); } /* Check for a breakpoint */ if (_wcsnicmp(KeyValueInformation->Name, L"BreakPointOnEntry", KeyValueInformation->NameLength/2) == 0) { DPRINT1("Breakpoint on entry requested!\n"); DbgBreakPoint(); } /* Get DisableSynchronousTransfers */ if (_wcsnicmp(KeyValueInformation->Name, L"DisableSynchronousTransfers", KeyValueInformation->NameLength/2) == 0) { DeviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER; DPRINT("Synch transfers disabled\n"); } /* Get DisableDisconnects */ if (_wcsnicmp(KeyValueInformation->Name, L"DisableDisconnects", KeyValueInformation->NameLength/2) == 0) { DeviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_DISCONNECT; DPRINT("Disconnects disabled\n"); } /* Get DisableTaggedQueuing */ if (_wcsnicmp(KeyValueInformation->Name, L"DisableTaggedQueuing", KeyValueInformation->NameLength/2) == 0) { InternalConfigInfo->DisableTaggedQueueing = TRUE; DPRINT("Tagged queueing disabled\n"); } /* Get DisableMultipleRequests */ if (_wcsnicmp(KeyValueInformation->Name, L"DisableMultipleRequests", KeyValueInformation->NameLength/2) == 0) { InternalConfigInfo->DisableMultipleLun = TRUE; DPRINT("Multiple requests disabled\n"); } /* Get DriverParameters */ if (_wcsnicmp(KeyValueInformation->Name, L"DriverParameters", KeyValueInformation->NameLength/2) == 0) { /* Skip if nothing */ if (KeyValueInformation->DataLength == 0) continue; /* If there was something previously allocated - free it */ if (InternalConfigInfo->Parameter != NULL) ExFreePool(InternalConfigInfo->Parameter); /* Allocate it */ InternalConfigInfo->Parameter = ExAllocatePoolWithTag(NonPagedPool, KeyValueInformation->DataLength, TAG_SCSIPORT); if (InternalConfigInfo->Parameter != NULL) { if (KeyValueInformation->Type != REG_SZ) { /* Just copy */ RtlCopyMemory( InternalConfigInfo->Parameter, (PCCHAR)KeyValueInformation + KeyValueInformation->DataOffset, KeyValueInformation->DataLength); } else { /* If it's a unicode string, convert it to ansi */ UnicodeString.Length = (USHORT)KeyValueInformation->DataLength; UnicodeString.MaximumLength = (USHORT)KeyValueInformation->DataLength; UnicodeString.Buffer = (PWSTR)((PCCHAR)KeyValueInformation + KeyValueInformation->DataOffset); AnsiString.Length = 0; AnsiString.MaximumLength = (USHORT)KeyValueInformation->DataLength; AnsiString.Buffer = (PCHAR)InternalConfigInfo->Parameter; Status = RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, FALSE); /* In case of error, free the allocated space */ if (!NT_SUCCESS(Status)) { ExFreePool(InternalConfigInfo->Parameter); InternalConfigInfo->Parameter = NULL; } } } DPRINT("Found driver parameter\n"); } /* Get MaximumSGList */ if (_wcsnicmp(KeyValueInformation->Name, L"MaximumSGList", KeyValueInformation->NameLength/2) == 0) { if (KeyValueInformation->Type != REG_DWORD) { DPRINT("Bad data type for MaximumSGList\n"); continue; } ConfigInfo->NumberOfPhysicalBreaks = *((PUCHAR)(Buffer + KeyValueInformation->DataOffset)); /* Check / fix */ if (ConfigInfo->NumberOfPhysicalBreaks > SCSI_MAXIMUM_PHYSICAL_BREAKS) { ConfigInfo->NumberOfPhysicalBreaks = SCSI_MAXIMUM_PHYSICAL_BREAKS; } else if (ConfigInfo->NumberOfPhysicalBreaks < SCSI_MINIMUM_PHYSICAL_BREAKS) { ConfigInfo->NumberOfPhysicalBreaks = SCSI_MINIMUM_PHYSICAL_BREAKS; } DPRINT("MaximumSGList = %d\n", ConfigInfo->NumberOfPhysicalBreaks); } /* Get NumberOfRequests */ if (_wcsnicmp(KeyValueInformation->Name, L"NumberOfRequests", KeyValueInformation->NameLength/2) == 0) { if (KeyValueInformation->Type != REG_DWORD) { DPRINT("NumberOfRequests has wrong data type\n"); continue; } DeviceExtension->RequestsNumber = *((PUCHAR)(Buffer + KeyValueInformation->DataOffset)); /* Check / fix */ if (DeviceExtension->RequestsNumber < 16) { DeviceExtension->RequestsNumber = 16; } else if (DeviceExtension->RequestsNumber > 512) { DeviceExtension->RequestsNumber = 512; } DPRINT("Number Of Requests = %d\n", DeviceExtension->RequestsNumber); } /* Get resource list */ if (_wcsnicmp(KeyValueInformation->Name, L"ResourceList", KeyValueInformation->NameLength/2) == 0 || _wcsnicmp(KeyValueInformation->Name, L"Configuration Data", KeyValueInformation->NameLength/2) == 0 ) { if (KeyValueInformation->Type != REG_FULL_RESOURCE_DESCRIPTOR || KeyValueInformation->DataLength < sizeof(REG_FULL_RESOURCE_DESCRIPTOR)) { DPRINT("Bad data type for ResourceList\n"); continue; } else { DPRINT("Found ResourceList\n"); } FullResource = (PCM_FULL_RESOURCE_DESCRIPTOR)(Buffer + KeyValueInformation->DataOffset); /* Copy some info from it */ InternalConfigInfo->BusNumber = FullResource->BusNumber; ConfigInfo->SystemIoBusNumber = FullResource->BusNumber; /* Loop through it */ for (Count = 0; Count < FullResource->PartialResourceList.Count; Count++) { /* Get partial descriptor */ PartialDescriptor = &FullResource->PartialResourceList.PartialDescriptors[Count]; /* Check datalength */ if ((ULONG)((PCHAR)(PartialDescriptor + 1) - (PCHAR)FullResource) > KeyValueInformation->DataLength) { DPRINT("Resource data is of incorrect size\n"); break; } switch (PartialDescriptor->Type) { case CmResourceTypePort: if (RangeCount >= ConfigInfo->NumberOfAccessRanges) { DPRINT("Too many access ranges\n"); continue; } InternalConfigInfo->AccessRanges[RangeCount].RangeInMemory = FALSE; InternalConfigInfo->AccessRanges[RangeCount].RangeStart = PartialDescriptor->u.Port.Start; InternalConfigInfo->AccessRanges[RangeCount].RangeLength = PartialDescriptor->u.Port.Length; RangeCount++; break; case CmResourceTypeMemory: if (RangeCount >= ConfigInfo->NumberOfAccessRanges) { DPRINT("Too many access ranges\n"); continue; } InternalConfigInfo->AccessRanges[RangeCount].RangeInMemory = TRUE; InternalConfigInfo->AccessRanges[RangeCount].RangeStart = PartialDescriptor->u.Memory.Start; InternalConfigInfo->AccessRanges[RangeCount].RangeLength = PartialDescriptor->u.Memory.Length; RangeCount++; break; case CmResourceTypeInterrupt: if (Interrupt == 0) { ConfigInfo->BusInterruptLevel = PartialDescriptor->u.Interrupt.Level; ConfigInfo->BusInterruptVector = PartialDescriptor->u.Interrupt.Vector; ConfigInfo->InterruptMode = (PartialDescriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED) ? Latched : LevelSensitive; } else if (Interrupt == 1) { ConfigInfo->BusInterruptLevel2 = PartialDescriptor->u.Interrupt.Level; ConfigInfo->BusInterruptVector2 = PartialDescriptor->u.Interrupt.Vector; ConfigInfo->InterruptMode2 = (PartialDescriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED) ? Latched : LevelSensitive; } Interrupt++; break; case CmResourceTypeDma: if (Dma == 0) { ConfigInfo->DmaChannel = PartialDescriptor->u.Dma.Channel; ConfigInfo->DmaPort = PartialDescriptor->u.Dma.Port; if (PartialDescriptor->Flags & CM_RESOURCE_DMA_8) ConfigInfo->DmaWidth = Width8Bits; else if ((PartialDescriptor->Flags & CM_RESOURCE_DMA_16) || (PartialDescriptor->Flags & CM_RESOURCE_DMA_8_AND_16)) //??? ConfigInfo->DmaWidth = Width16Bits; else if (PartialDescriptor->Flags & CM_RESOURCE_DMA_32) ConfigInfo->DmaWidth = Width32Bits; } else if (Dma == 1) { ConfigInfo->DmaChannel2 = PartialDescriptor->u.Dma.Channel; ConfigInfo->DmaPort2 = PartialDescriptor->u.Dma.Port; if (PartialDescriptor->Flags & CM_RESOURCE_DMA_8) ConfigInfo->DmaWidth2 = Width8Bits; else if ((PartialDescriptor->Flags & CM_RESOURCE_DMA_16) || (PartialDescriptor->Flags & CM_RESOURCE_DMA_8_AND_16)) //??? ConfigInfo->DmaWidth2 = Width16Bits; else if (PartialDescriptor->Flags & CM_RESOURCE_DMA_32) ConfigInfo->DmaWidth2 = Width32Bits; } Dma++; break; case CmResourceTypeDeviceSpecific: if (PartialDescriptor->u.DeviceSpecificData.DataSize < sizeof(CM_SCSI_DEVICE_DATA) || (PCHAR) (PartialDescriptor + 1) - (PCHAR)FullResource + PartialDescriptor->u.DeviceSpecificData.DataSize > KeyValueInformation->DataLength) { DPRINT("Resource data length is incorrect"); break; } /* Set only one field from it */ ScsiDeviceData = (PCM_SCSI_DEVICE_DATA) (PartialDescriptor+1); ConfigInfo->InitiatorBusId[0] = ScsiDeviceData->HostIdentifier; break; } } } } } NTSTATUS NTAPI SpQueryDeviceCallout(IN PVOID Context, IN PUNICODE_STRING PathName, IN INTERFACE_TYPE BusType, IN ULONG BusNumber, IN PKEY_VALUE_FULL_INFORMATION *BusInformation, IN CONFIGURATION_TYPE ControllerType, IN ULONG ControllerNumber, IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation, IN CONFIGURATION_TYPE PeripheralType, IN ULONG PeripheralNumber, IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation) { PBOOLEAN Found = (PBOOLEAN)Context; /* We just set our Found variable to TRUE */ *Found = TRUE; return STATUS_SUCCESS; } IO_ALLOCATION_ACTION NTAPI ScsiPortAllocateAdapterChannel(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID MapRegisterBase, IN PVOID Context) { KIRQL Irql; PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; /* Guard access with the spinlock */ KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql); /* Save MapRegisterBase we've got here */ DeviceExtension->MapRegisterBase = MapRegisterBase; /* Start pending request */ KeSynchronizeExecution(DeviceExtension->Interrupt[0], ScsiPortStartPacket, DeviceObject); /* Release spinlock we took */ KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql); return KeepObject; } #undef ScsiPortConvertPhysicalAddressToUlong /* * @implemented */ ULONG NTAPI ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address) { DPRINT("ScsiPortConvertPhysicalAddressToUlong()\n"); return(Address.u.LowPart); }