From a97c6e0aa92749a4c29f180e42a63d0fdec1d2d4 Mon Sep 17 00:00:00 2001 From: Victor Perevertkin Date: Wed, 28 Oct 2020 02:42:56 +0300 Subject: [PATCH] [SCSIPORT] Make the driver PnP-aware Basic functions are implemented in order to work in PnP stack, only legacy (non-pnp) miniport drivers are supported. Tested mostly with uniata CORE-17132 --- drivers/storage/port/scsiport/CMakeLists.txt | 17 +- drivers/storage/port/scsiport/fdo.c | 582 ++++++++++-------- drivers/storage/port/scsiport/guid.c | 11 + drivers/storage/port/scsiport/ioctl.c | 525 ++++++++++++---- drivers/storage/port/scsiport/pdo.c | 603 +++++++++++++++++-- drivers/storage/port/scsiport/power.c | 41 ++ drivers/storage/port/scsiport/registry.c | 405 ++++++------- drivers/storage/port/scsiport/scsi.c | 204 +++---- drivers/storage/port/scsiport/scsiport.c | 433 +++++++------ drivers/storage/port/scsiport/scsiport.h | 192 +++--- drivers/storage/port/scsiport/scsitypes.h | 124 ++++ 11 files changed, 2087 insertions(+), 1050 deletions(-) create mode 100644 drivers/storage/port/scsiport/guid.c create mode 100644 drivers/storage/port/scsiport/power.c create mode 100644 drivers/storage/port/scsiport/scsitypes.h diff --git a/drivers/storage/port/scsiport/CMakeLists.txt b/drivers/storage/port/scsiport/CMakeLists.txt index 13c4407e4d9..e0f3ce08a78 100644 --- a/drivers/storage/port/scsiport/CMakeLists.txt +++ b/drivers/storage/port/scsiport/CMakeLists.txt @@ -2,20 +2,25 @@ spec2def(scsiport.sys scsiport.spec ADD_IMPORTLIB) list(APPEND SOURCE - fdo.c - ioctl.c - pdo.c - registry.c - scsi.c + fdo.c + ioctl.c + pdo.c + power.c + registry.c + scsi.c scsiport.c stubs.c) +list(APPEND PCH_SKIP_SOURCE + guid.c) + add_library(scsiport MODULE ${SOURCE} + ${PCH_SKIP_SOURCE} scsiport.rc ${CMAKE_CURRENT_BINARY_DIR}/scsiport.def) -add_pch(scsiport scsiport.h "") +add_pch(scsiport scsiport.h "${PCH_SKIP_SOURCE}") set_module_type(scsiport kernelmodedriver) add_importlibs(scsiport ntoskrnl hal) add_cd_file(TARGET scsiport DESTINATION reactos/system32/drivers NO_CAB FOR all) diff --git a/drivers/storage/port/scsiport/fdo.c b/drivers/storage/port/scsiport/fdo.c index 95a0f3b4ed5..2cc89ea7353 100644 --- a/drivers/storage/port/scsiport/fdo.c +++ b/drivers/storage/port/scsiport/fdo.c @@ -4,6 +4,7 @@ * PURPOSE: Adapter device object (FDO) support routines * COPYRIGHT: Eric Kohl (eric.kohl@reactos.org) * Aleksey Bragin (aleksey@reactos.org) + * 2020 Victor Perevertkin (victor.perevertkin@reactos.org) */ #include "scsiport.h" @@ -14,9 +15,8 @@ static NTSTATUS -SpiSendInquiry( - _In_ PDEVICE_OBJECT DeviceObject, - _Inout_ PSCSI_LUN_INFO LunInfo) +FdoSendInquiry( + _In_ PDEVICE_OBJECT DeviceObject) { IO_STATUS_BLOCK IoStatusBlock; PIO_STACK_LOCATION IrpStack; @@ -30,12 +30,12 @@ SpiSendInquiry( ULONG RetryCount = 0; SCSI_REQUEST_BLOCK Srb; PCDB Cdb; - PSCSI_PORT_LUN_EXTENSION LunExtension; - PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; - DPRINT("SpiSendInquiry() called\n"); + DPRINT("FdoSendInquiry() called\n"); - DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + PSCSI_PORT_LUN_EXTENSION LunExtension = DeviceObject->DeviceExtension; + PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = + LunExtension->Common.LowerDevice->DeviceExtension; InquiryBuffer = ExAllocatePoolWithTag(NonPagedPool, INQUIRYDATABUFFERSIZE, TAG_SCSIPORT); if (InquiryBuffer == NULL) @@ -80,9 +80,9 @@ SpiSendInquiry( Srb.Length = sizeof(SCSI_REQUEST_BLOCK); Srb.OriginalRequest = Irp; - Srb.PathId = LunInfo->PathId; - Srb.TargetId = LunInfo->TargetId; - Srb.Lun = LunInfo->Lun; + Srb.PathId = LunExtension->PathId; + Srb.TargetId = LunExtension->TargetId; + Srb.Lun = LunExtension->Lun; Srb.Function = SRB_FUNCTION_EXECUTE_SCSI; Srb.SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER; Srb.TimeOutValue = 4; @@ -101,7 +101,7 @@ SpiSendInquiry( /* Fill in CDB */ Cdb = (PCDB)Srb.Cdb; Cdb->CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY; - Cdb->CDB6INQUIRY.LogicalUnitNumber = LunInfo->Lun; + Cdb->CDB6INQUIRY.LogicalUnitNumber = LunExtension->Lun; Cdb->CDB6INQUIRY.AllocationLength = INQUIRYDATABUFFERSIZE; /* Call the driver */ @@ -110,7 +110,7 @@ SpiSendInquiry( /* Wait for it to complete */ if (Status == STATUS_PENDING) { - DPRINT("SpiSendInquiry(): Waiting for the driver to process request...\n"); + DPRINT("FdoSendInquiry(): Waiting for the driver to process request...\n"); KeWaitForSingleObject(&Event, Executive, KernelMode, @@ -119,12 +119,12 @@ SpiSendInquiry( Status = IoStatusBlock.Status; } - DPRINT("SpiSendInquiry(): Request processed by driver, status = 0x%08X\n", Status); + DPRINT("FdoSendInquiry(): Request processed by driver, status = 0x%08X\n", Status); if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_SUCCESS) { /* All fine, copy data over */ - RtlCopyMemory(LunInfo->InquiryData, + RtlCopyMemory(&LunExtension->InquiryData, InquiryBuffer, INQUIRYDATABUFFERSIZE); @@ -142,12 +142,7 @@ SpiSendInquiry( /* Something weird happened, deal with it (unfreeze the queue) */ KeepTrying = FALSE; - DPRINT("SpiSendInquiry(): the queue is frozen at TargetId %d\n", Srb.TargetId); - - LunExtension = SpiGetLunExtension(DeviceExtension, - LunInfo->PathId, - LunInfo->TargetId, - LunInfo->Lun); + DPRINT("FdoSendInquiry(): the queue is frozen at TargetId %d\n", Srb.TargetId); /* Clear frozen flag */ LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE; @@ -156,7 +151,7 @@ SpiSendInquiry( KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql); /* Process the request */ - SpiGetNextRequestFromLun(DeviceObject->DeviceExtension, LunExtension); + SpiGetNextRequestFromLun(DeviceExtension, LunExtension); /* SpiGetNextRequestFromLun() releases the spinlock, so we just lower irql back to what it was before */ @@ -166,10 +161,10 @@ SpiSendInquiry( /* Check if data overrun happened */ if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN) { - DPRINT("Data overrun at TargetId %d\n", LunInfo->TargetId); + DPRINT("Data overrun at TargetId %d\n", LunExtension->TargetId); /* Nothing dramatic, just copy data, but limiting the size */ - RtlCopyMemory(LunInfo->InquiryData, + RtlCopyMemory(&LunExtension->InquiryData, InquiryBuffer, (Srb.DataTransferLength > INQUIRYDATABUFFERSIZE) ? INQUIRYDATABUFFERSIZE : Srb.DataTransferLength); @@ -221,229 +216,141 @@ SpiSendInquiry( ExFreePoolWithTag(InquiryBuffer, TAG_SCSIPORT); ExFreePoolWithTag(SenseBuffer, TAG_SCSIPORT); - DPRINT("SpiSendInquiry() done with Status 0x%08X\n", Status); + DPRINT("FdoSendInquiry() done with Status 0x%08X\n", Status); return Status; } /* Scans all SCSI buses */ VOID -SpiScanAdapter( - _In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension) +FdoScanAdapter( + _In_ PSCSI_PORT_DEVICE_EXTENSION PortExtension) { - PSCSI_PORT_LUN_EXTENSION LunExtension; - ULONG Bus; - ULONG Target; - ULONG Lun; - PSCSI_BUS_SCAN_INFO BusScanInfo; - PSCSI_LUN_INFO LastLunInfo, LunInfo, LunInfoExists; - BOOLEAN DeviceExists; - ULONG Hint; - NTSTATUS Status; - ULONG DevicesFound; + NTSTATUS status; + UINT32 totalLUNs = PortExtension->TotalLUCount; - DPRINT("SpiScanAdapter() called\n"); + DPRINT("FdoScanAdapter() called\n"); /* Scan all buses */ - for (Bus = 0; Bus < DeviceExtension->BusNum; Bus++) + for (UINT8 pathId = 0; pathId < PortExtension->NumberOfBuses; pathId++) { - DPRINT(" Scanning bus %d\n", Bus); - DevicesFound = 0; + DPRINT(" Scanning bus/pathID %u\n", pathId); /* Get pointer to the scan information */ - BusScanInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus]; - - if (BusScanInfo) - { - /* Find the last LUN info in the list */ - LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus]->LunInfo; - LastLunInfo = LunInfo; - - while (LunInfo != NULL) - { - LastLunInfo = LunInfo; - LunInfo = LunInfo->Next; - } - } - else - { - /* We need to allocate this buffer */ - BusScanInfo = ExAllocatePoolWithTag(NonPagedPool, sizeof(SCSI_BUS_SCAN_INFO), TAG_SCSIPORT); - if (!BusScanInfo) - { - DPRINT1("Out of resources!\n"); - return; - } - - /* Store the pointer in the BusScanInfo array */ - DeviceExtension->BusesConfig->BusScanInfo[Bus] = BusScanInfo; - - /* Fill this struct (length and bus ids for now) */ - BusScanInfo->Length = sizeof(SCSI_BUS_SCAN_INFO); - BusScanInfo->LogicalUnitsCount = 0; - BusScanInfo->BusIdentifier = DeviceExtension->PortConfig->InitiatorBusId[Bus]; - BusScanInfo->LunInfo = NULL; - - /* Set pointer to the last LUN info to NULL */ - LastLunInfo = NULL; - } - - /* Create LUN information structure */ - LunInfo = ExAllocatePoolWithTag(PagedPool, sizeof(SCSI_LUN_INFO), TAG_SCSIPORT); - if (!LunInfo) - { - DPRINT1("Out of resources!\n"); - return; - } - - RtlZeroMemory(LunInfo, sizeof(SCSI_LUN_INFO)); - - /* Create LunExtension */ - LunExtension = SpiAllocateLunExtension(DeviceExtension); + PSCSI_BUS_INFO currentBus = &PortExtension->Buses[pathId]; /* And send INQUIRY to every target */ - for (Target = 0; Target < DeviceExtension->PortConfig->MaximumNumberOfTargets; Target++) + for (UINT8 targetId = 0; + targetId < PortExtension->PortConfig->MaximumNumberOfTargets; + targetId++) { + BOOLEAN targetFound = FALSE; + /* TODO: Support scan bottom-up */ /* Skip if it's the same address */ - if (Target == BusScanInfo->BusIdentifier) - continue; - - /* Try to find an existing device here */ - DeviceExists = FALSE; - LunInfoExists = BusScanInfo->LunInfo; - - /* Find matching address on this bus */ - while (LunInfoExists) - { - if (LunInfoExists->TargetId == Target) - { - DeviceExists = TRUE; - break; - } - - /* Advance to the next one */ - LunInfoExists = LunInfoExists->Next; - } - - /* No need to bother rescanning, since we already did that before */ - if (DeviceExists) + if (targetId == currentBus->BusIdentifier) continue; /* Scan all logical units */ - for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++) + for (UINT8 lun = 0; lun < PortExtension->MaxLunCount; lun++) { - if ((!LunExtension) || (!LunInfo)) - break; + // try to find an existing device + PSCSI_PORT_LUN_EXTENSION lunExt = GetLunByPath(PortExtension, + pathId, + targetId, + lun); - /* Add extension to the list */ - Hint = (Target + Lun) % LUS_NUMBER; - LunExtension->Next = DeviceExtension->LunExtensionList[Hint]; - DeviceExtension->LunExtensionList[Hint] = LunExtension; - - /* Fill Path, Target, Lun fields */ - LunExtension->PathId = LunInfo->PathId = (UCHAR)Bus; - LunExtension->TargetId = LunInfo->TargetId = (UCHAR)Target; - LunExtension->Lun = LunInfo->Lun = (UCHAR)Lun; - - /* Set flag to prevent race conditions */ - LunExtension->Flags |= SCSI_PORT_SCAN_IN_PROGRESS; - - /* Zero LU extension contents */ - if (DeviceExtension->LunExtensionSize) + if (lunExt) { - RtlZeroMemory(LunExtension + 1, - DeviceExtension->LunExtensionSize); + // check if the device still exists + status = FdoSendInquiry(lunExt->Common.DeviceObject); + if (!NT_SUCCESS(status)) + { + // remove the device + UNIMPLEMENTED; + __debugbreak(); + } + + if (lunExt->InquiryData.DeviceTypeQualifier == DEVICE_QUALIFIER_NOT_SUPPORTED) + { + // remove the device + UNIMPLEMENTED; + __debugbreak(); + } + + /* Decide whether we are continuing or not */ + if (status == STATUS_INVALID_DEVICE_REQUEST) + continue; + else + break; } - /* Finally send the inquiry command */ - Status = SpiSendInquiry(DeviceExtension->DeviceObject, LunInfo); + // create a new LUN device + PDEVICE_OBJECT lunPDO = PdoCreateLunDevice(PortExtension); + if (!lunPDO) + { + continue; + } - if (NT_SUCCESS(Status)) + lunExt = lunPDO->DeviceExtension; + + lunExt->PathId = pathId; + lunExt->TargetId = targetId; + lunExt->Lun = lun; + + DPRINT("Add PDO to list: PDO: %p, FDOExt: %p, PDOExt: %p\n", lunPDO, PortExtension, lunExt); + + /* Set flag to prevent race conditions */ + lunExt->Flags |= SCSI_PORT_SCAN_IN_PROGRESS; + + /* Finally send the inquiry command */ + status = FdoSendInquiry(lunPDO); + + if (NT_SUCCESS(status)) { /* Let's see if we really found a device */ - PINQUIRYDATA InquiryData = (PINQUIRYDATA)LunInfo->InquiryData; + PINQUIRYDATA InquiryData = &lunExt->InquiryData; /* Check if this device is unsupported */ if (InquiryData->DeviceTypeQualifier == DEVICE_QUALIFIER_NOT_SUPPORTED) { - DeviceExtension->LunExtensionList[Hint] = - DeviceExtension->LunExtensionList[Hint]->Next; - + IoDeleteDevice(lunPDO); continue; } /* Clear the "in scan" flag */ - LunExtension->Flags &= ~SCSI_PORT_SCAN_IN_PROGRESS; + lunExt->Flags &= ~SCSI_PORT_SCAN_IN_PROGRESS; - DPRINT("SpiScanAdapter(): Found device of type %d at bus %d tid %d lun %d\n", - InquiryData->DeviceType, Bus, Target, Lun); + DPRINT("FdoScanAdapter(): Found device of type %d at bus %d tid %d lun %d\n", + InquiryData->DeviceType, pathId, targetId, lun); - /* - * Cache the inquiry data into the LUN extension (or alternatively - * we could save a pointer to LunInfo within the LunExtension?) - */ - RtlCopyMemory(&LunExtension->InquiryData, - InquiryData, - INQUIRYDATABUFFERSIZE); + InsertTailList(¤tBus->LunsListHead, &lunExt->LunEntry); - /* Add this info to the linked list */ - LunInfo->Next = NULL; - if (LastLunInfo) - LastLunInfo->Next = LunInfo; - else - BusScanInfo->LunInfo = LunInfo; + DPRINT1("SCSIPORT: created lun device: %p Status: %x\n", lunPDO, status); - /* Store the last LUN info */ - LastLunInfo = LunInfo; - - /* Store DeviceObject */ - LunInfo->DeviceObject = DeviceExtension->DeviceObject; - - /* Allocate another buffer */ - LunInfo = ExAllocatePoolWithTag(PagedPool, sizeof(SCSI_LUN_INFO), TAG_SCSIPORT); - if (!LunInfo) - { - DPRINT1("Out of resources!\n"); - break; - } - - RtlZeroMemory(LunInfo, sizeof(SCSI_LUN_INFO)); - - /* Create a new LU extension */ - LunExtension = SpiAllocateLunExtension(DeviceExtension); - - DevicesFound++; + totalLUNs++; + currentBus->LogicalUnitsCount++; + targetFound = TRUE; } else { - /* Remove this LUN from the list */ - DeviceExtension->LunExtensionList[Hint] = - DeviceExtension->LunExtensionList[Hint]->Next; - /* Decide whether we are continuing or not */ - if (Status == STATUS_INVALID_DEVICE_REQUEST) + if (status == STATUS_INVALID_DEVICE_REQUEST) continue; else break; } } + + if (targetFound) + { + currentBus->TargetsCount++; + } } - - /* Free allocated buffers */ - if (LunExtension) - ExFreePoolWithTag(LunExtension, TAG_SCSIPORT); - - if (LunInfo) - ExFreePoolWithTag(LunInfo, TAG_SCSIPORT); - - /* Sum what we found */ - BusScanInfo->LogicalUnitsCount += (UCHAR)DevicesFound; - DPRINT(" Found %d devices on bus %d\n", DevicesFound, Bus); } - DPRINT("SpiScanAdapter() done\n"); + PortExtension->TotalLUCount = totalLUNs; } /** @@ -456,11 +363,11 @@ SpiScanAdapter( * @return NTSTATUS of the operation */ NTSTATUS -CallHWInitialize( +FdoCallHWInitialize( _In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension) { PPORT_CONFIGURATION_INFORMATION PortConfig = DeviceExtension->PortConfig; - NTSTATUS Status = STATUS_SUCCESS; + NTSTATUS Status; KIRQL OldIrql; /* Deal with interrupts */ @@ -508,9 +415,13 @@ CallHWInitialize( } if (DeviceExtension->InterruptCount == 1 || Dirql[0] > Dirql[1]) + { MaxDirql = Dirql[0]; + } else + { MaxDirql = Dirql[1]; + } for (i = 0; i < DeviceExtension->InterruptCount; i++) { @@ -525,10 +436,16 @@ CallHWInitialize( InterruptShareable = FALSE; } - Status = IoConnectInterrupt( - &DeviceExtension->Interrupt[i], (PKSERVICE_ROUTINE)ScsiPortIsr, DeviceExtension, - &DeviceExtension->IrqLock, MappedIrq[i], Dirql[i], MaxDirql, InterruptMode[i], - InterruptShareable, Affinity[i], FALSE); + Status = IoConnectInterrupt(&DeviceExtension->Interrupt[i], + ScsiPortIsr, + DeviceExtension, + &DeviceExtension->IrqLock, + MappedIrq[i], Dirql[i], + MaxDirql, + InterruptMode[i], + InterruptShareable, + Affinity[i], + FALSE); if (!(NT_SUCCESS(Status))) { @@ -537,9 +454,6 @@ CallHWInitialize( return Status; } } - - if (!NT_SUCCESS(Status)) - return Status; } /* Save IoAddress (from access ranges) */ @@ -583,98 +497,96 @@ CallHWInitialize( if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED) { /* Call DPC right away, because we're already at DISPATCH_LEVEL */ - ScsiPortDpcForIsr(NULL, DeviceExtension->DeviceObject, NULL, NULL); + ScsiPortDpcForIsr(NULL, DeviceExtension->Common.DeviceObject, NULL, NULL); } /* Lower irql back to what it was */ KeLowerIrql(OldIrql); - return Status; + return STATUS_SUCCESS; } -VOID -SpiCleanupAfterInit( +NTSTATUS +FdoRemoveAdapter( _In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension) { - PSCSI_LUN_INFO LunInfo; - PVOID Ptr; - ULONG Bus, Lun; + IoStopTimer(DeviceExtension->Common.DeviceObject); - /* Check if we have something to clean up */ - if (DeviceExtension == NULL) - return; + // release device interface + if (DeviceExtension->InterfaceName.Buffer) + { + IoSetDeviceInterfaceState(&DeviceExtension->InterfaceName, FALSE); - /* Stop the timer */ - IoStopTimer(DeviceExtension->DeviceObject); + RtlFreeUnicodeString(&DeviceExtension->InterfaceName); + RtlInitUnicodeString(&DeviceExtension->InterfaceName, NULL); + } - /* Disconnect the interrupts */ + // remove the dos device link + WCHAR dosNameBuffer[12]; + UNICODE_STRING dosDeviceName; + + swprintf(dosNameBuffer, L"\\??\\Scsi%lu:", DeviceExtension->PortNumber); + RtlInitUnicodeString(&dosDeviceName, dosNameBuffer); + + IoDeleteSymbolicLink(&dosDeviceName); // don't check the result + + // decrease the port count + if (DeviceExtension->DeviceStarted) + { + PCONFIGURATION_INFORMATION sysConfig = IoGetConfigurationInformation(); + sysConfig->ScsiPortCount--; + } + + // disconnect the interrupts while (DeviceExtension->InterruptCount) { if (DeviceExtension->Interrupt[--DeviceExtension->InterruptCount]) IoDisconnectInterrupt(DeviceExtension->Interrupt[DeviceExtension->InterruptCount]); } - /* Delete ConfigInfo */ - if (DeviceExtension->BusesConfig) + // FIXME: delete LUNs + if (DeviceExtension->Buses) { - for (Bus = 0; Bus < DeviceExtension->BusNum; Bus++) + for (UINT8 pathId = 0; pathId < DeviceExtension->NumberOfBuses; pathId++) { - if (!DeviceExtension->BusesConfig->BusScanInfo[Bus]) - continue; - - LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus]->LunInfo; - - while (LunInfo) + PSCSI_BUS_INFO bus = &DeviceExtension->Buses[pathId]; + if (bus->RegistryMapKey) { - /* Free current, but save pointer to the next one */ - Ptr = LunInfo->Next; - ExFreePool(LunInfo); - LunInfo = Ptr; + ZwDeleteKey(bus->RegistryMapKey); + ZwClose(bus->RegistryMapKey); + bus->RegistryMapKey = NULL; } - - ExFreePool(DeviceExtension->BusesConfig->BusScanInfo[Bus]); } - ExFreePool(DeviceExtension->BusesConfig); + ExFreePoolWithTag(DeviceExtension->Buses, TAG_SCSIPORT); } /* Free PortConfig */ if (DeviceExtension->PortConfig) - ExFreePool(DeviceExtension->PortConfig); - - /* Free LUNs*/ - for(Lun = 0; Lun < LUS_NUMBER; Lun++) { - while (DeviceExtension->LunExtensionList[Lun]) - { - Ptr = DeviceExtension->LunExtensionList[Lun]; - DeviceExtension->LunExtensionList[Lun] = DeviceExtension->LunExtensionList[Lun]->Next; - - ExFreePool(Ptr); - } + ExFreePoolWithTag(DeviceExtension->PortConfig, TAG_SCSIPORT); } /* Free common buffer (if it exists) */ - if (DeviceExtension->SrbExtensionBuffer != NULL && - DeviceExtension->CommonBufferLength != 0) + if (DeviceExtension->SrbExtensionBuffer != NULL && DeviceExtension->CommonBufferLength != 0) { - if (!DeviceExtension->AdapterObject) - { - ExFreePool(DeviceExtension->SrbExtensionBuffer); - } - else - { - HalFreeCommonBuffer(DeviceExtension->AdapterObject, - DeviceExtension->CommonBufferLength, - DeviceExtension->PhysicalAddress, - DeviceExtension->SrbExtensionBuffer, - FALSE); - } + if (!DeviceExtension->AdapterObject) + { + ExFreePoolWithTag(DeviceExtension->SrbExtensionBuffer, TAG_SCSIPORT); + } + else + { + HalFreeCommonBuffer(DeviceExtension->AdapterObject, + DeviceExtension->CommonBufferLength, + DeviceExtension->PhysicalAddress, + DeviceExtension->SrbExtensionBuffer, + FALSE); + } } /* Free SRB info */ if (DeviceExtension->SrbInfo != NULL) - ExFreePool(DeviceExtension->SrbInfo); + ExFreePoolWithTag(DeviceExtension->SrbInfo, TAG_SCSIPORT); /* Unmap mapped addresses */ while (DeviceExtension->MappedAddressList != NULL) @@ -682,13 +594,161 @@ SpiCleanupAfterInit( MmUnmapIoSpace(DeviceExtension->MappedAddressList->MappedAddress, DeviceExtension->MappedAddressList->NumberOfBytes); - Ptr = DeviceExtension->MappedAddressList; + PVOID ptr = DeviceExtension->MappedAddressList; DeviceExtension->MappedAddressList = DeviceExtension->MappedAddressList->NextMappedAddress; - ExFreePool(Ptr); + ExFreePoolWithTag(ptr, TAG_SCSIPORT); } - /* Finally delete the device object */ - DPRINT("Deleting device %p\n", DeviceExtension->DeviceObject); - IoDeleteDevice(DeviceExtension->DeviceObject); + IoDeleteDevice(DeviceExtension->Common.DeviceObject); + + return STATUS_SUCCESS; +} + +NTSTATUS +FdoStartAdapter( + _In_ PSCSI_PORT_DEVICE_EXTENSION PortExtension) +{ + WCHAR dosNameBuffer[12]; + UNICODE_STRING dosDeviceName; + NTSTATUS status; + + // Start our timer + IoStartTimer(PortExtension->Common.DeviceObject); + + // Create the dos device link + swprintf(dosNameBuffer, L"\\??\\Scsi%u:", PortExtension->PortNumber); + RtlInitUnicodeString(&dosDeviceName, dosNameBuffer); + status = IoCreateSymbolicLink(&dosDeviceName, &PortExtension->DeviceName); + if (!NT_SUCCESS(status)) + { + return status; + } + + // start building a device map + RegistryInitAdapterKey(PortExtension); + + // increase the port count + PCONFIGURATION_INFORMATION sysConfig = IoGetConfigurationInformation(); + sysConfig->ScsiPortCount++; + + // Register and enable the device interface + status = IoRegisterDeviceInterface(PortExtension->Common.DeviceObject, + &StoragePortClassGuid, + NULL, + &PortExtension->InterfaceName); + DPRINT("IoRegisterDeviceInterface status: %x, InterfaceName: %wZ\n", + status, &PortExtension->InterfaceName); + + if (NT_SUCCESS(status)) + { + IoSetDeviceInterfaceState(&PortExtension->InterfaceName, TRUE); + } + + PortExtension->DeviceStarted = TRUE; + + return STATUS_SUCCESS; +} + +static +NTSTATUS +FdoHandleDeviceRelations( + _In_ PSCSI_PORT_DEVICE_EXTENSION PortExtension, + _Inout_ PIRP Irp) +{ + PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp); + + // FDO always only handles bus relations + if (ioStack->Parameters.QueryDeviceRelations.Type == BusRelations) + { + FdoScanAdapter(PortExtension); + DPRINT("Found %u PD objects, FDOExt: %p\n", PortExtension->TotalLUCount, PortExtension); + + // check that no filter driver has messed up this + ASSERT(Irp->IoStatus.Information == 0); + + PDEVICE_RELATIONS deviceRelations = + ExAllocatePoolWithTag(PagedPool, + (sizeof(DEVICE_RELATIONS) + + sizeof(PDEVICE_OBJECT) * (PortExtension->TotalLUCount - 1)), + TAG_SCSIPORT); + + if (!deviceRelations) + { + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_INSUFFICIENT_RESOURCES; + } + + deviceRelations->Count = 0; + + for (UINT8 pathId = 0; pathId < PortExtension->NumberOfBuses; pathId++) + { + PSCSI_BUS_INFO bus = &PortExtension->Buses[pathId]; + + for (PLIST_ENTRY lunEntry = bus->LunsListHead.Flink; + lunEntry != &bus->LunsListHead; + lunEntry = lunEntry->Flink) + { + PSCSI_PORT_LUN_EXTENSION lunExt = + CONTAINING_RECORD(lunEntry, SCSI_PORT_LUN_EXTENSION, LunEntry); + + deviceRelations->Objects[deviceRelations->Count++] = lunExt->Common.DeviceObject; + ObReferenceObject(lunExt->Common.DeviceObject); + } + } + + ASSERT(deviceRelations->Count == PortExtension->TotalLUCount); + + Irp->IoStatus.Information = (ULONG_PTR)deviceRelations; + Irp->IoStatus.Status = STATUS_SUCCESS; + } + + IoSkipCurrentIrpStackLocation(Irp); + return IoCallDriver(PortExtension->Common.LowerDevice, Irp); +} + +NTSTATUS +FdoDispatchPnp( + _In_ PDEVICE_OBJECT DeviceObject, + _Inout_ PIRP Irp) +{ + PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp); + PSCSI_PORT_DEVICE_EXTENSION portExt = DeviceObject->DeviceExtension; + NTSTATUS status; + + ASSERT(portExt->Common.IsFDO); + + DPRINT("FDO PnP request %s\n", GetIRPMinorFunctionString(ioStack->MinorFunction)); + + switch (ioStack->MinorFunction) + { + case IRP_MN_START_DEVICE: + { + // as we don't support PnP yet, this is a no-op for us + // (FdoStartAdapter is being called during initialization for legacy miniports) + status = STATUS_SUCCESS; + // status = FdoStartAdapter(DeviceExtension); + break; + } + case IRP_MN_QUERY_DEVICE_RELATIONS: + { + return FdoHandleDeviceRelations(portExt, Irp); + } + default: + { + // forward irp to next device object + IoCopyCurrentIrpStackLocationToNext(Irp); + return IoCallDriver(portExt->Common.LowerDevice, Irp); + } + } + + if (status != STATUS_PENDING) + { + Irp->IoStatus.Status = status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + } + + return status; } diff --git a/drivers/storage/port/scsiport/guid.c b/drivers/storage/port/scsiport/guid.c new file mode 100644 index 00000000000..757901b4222 --- /dev/null +++ b/drivers/storage/port/scsiport/guid.c @@ -0,0 +1,11 @@ +/* DO NOT USE THE PRECOMPILED HEADER FOR THIS FILE! */ + +#include +#include +#include +#include + +#define DEVICE_TYPE ULONG +#include + +/* NO CODE HERE, THIS IS JUST REQUIRED FOR THE GUID DEFINITIONS */ diff --git a/drivers/storage/port/scsiport/ioctl.c b/drivers/storage/port/scsiport/ioctl.c index 08de2260961..7346f7f3228 100644 --- a/drivers/storage/port/scsiport/ioctl.c +++ b/drivers/storage/port/scsiport/ioctl.c @@ -4,6 +4,7 @@ * PURPOSE: IOCTL handlers * COPYRIGHT: Eric Kohl (eric.kohl@reactos.org) * Aleksey Bragin (aleksey@reactos.org) + * 2020 Victor Perevertkin (victor.perevertkin@reactos.org) */ #include "scsiport.h" @@ -19,13 +20,10 @@ SpiGetInquiryData( _In_ PIRP Irp) { ULONG InquiryDataSize; - PSCSI_LUN_INFO LunInfo; - ULONG BusCount, LunCount, Length; + ULONG BusCount, Length; PIO_STACK_LOCATION IrpStack; PSCSI_ADAPTER_BUS_INFO AdapterBusInfo; PSCSI_INQUIRY_DATA InquiryData; - PSCSI_BUS_DATA BusData; - ULONG Bus; PUCHAR Buffer; DPRINT("SpiGetInquiryData() called\n"); @@ -35,22 +33,15 @@ SpiGetInquiryData( Buffer = Irp->AssociatedIrp.SystemBuffer; /* Initialize bus and LUN counters */ - BusCount = DeviceExtension->BusesConfig->NumberOfBuses; - LunCount = 0; - - /* Calculate total number of LUNs */ - for (Bus = 0; Bus < BusCount; Bus++) - LunCount += DeviceExtension->BusesConfig->BusScanInfo[Bus]->LogicalUnitsCount; + BusCount = DeviceExtension->NumberOfBuses; /* Calculate size of inquiry data, rounding up to sizeof(ULONG) */ - InquiryDataSize = - ((sizeof(SCSI_INQUIRY_DATA) - 1 + INQUIRYDATABUFFERSIZE + - sizeof(ULONG) - 1) & ~(sizeof(ULONG) - 1)); + InquiryDataSize = ALIGN_UP(sizeof(SCSI_INQUIRY_DATA) - 1 + INQUIRYDATABUFFERSIZE, ULONG); /* Calculate data size */ Length = sizeof(SCSI_ADAPTER_BUS_INFO) + (BusCount - 1) * sizeof(SCSI_BUS_DATA); - Length += InquiryDataSize * LunCount; + Length += InquiryDataSize * DeviceExtension->TotalLUCount; /* Check, if all data is going to fit into provided buffer */ if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < Length) @@ -73,47 +64,47 @@ SpiGetInquiryData( (BusCount - 1) * sizeof(SCSI_BUS_DATA)); /* Loop each bus */ - for (Bus = 0; Bus < BusCount; Bus++) + for (UINT8 pathId = 0; pathId < DeviceExtension->NumberOfBuses; pathId++) { - BusData = &AdapterBusInfo->BusData[Bus]; + PSCSI_BUS_DATA BusData = &AdapterBusInfo->BusData[pathId]; /* Calculate and save an offset of the inquiry data */ BusData->InquiryDataOffset = (ULONG)((PUCHAR)InquiryData - Buffer); - /* Get a pointer to the LUN information structure */ - LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus]->LunInfo; - /* Store Initiator Bus Id */ - BusData->InitiatorBusId = - DeviceExtension->BusesConfig->BusScanInfo[Bus]->BusIdentifier; + BusData->InitiatorBusId = DeviceExtension->Buses[pathId].BusIdentifier; /* Store LUN count */ - BusData->NumberOfLogicalUnits = - DeviceExtension->BusesConfig->BusScanInfo[Bus]->LogicalUnitsCount; + BusData->NumberOfLogicalUnits = DeviceExtension->Buses[pathId].LogicalUnitsCount; /* Loop all LUNs */ - while (LunInfo != NULL) + PSCSI_BUS_INFO bus = &DeviceExtension->Buses[pathId]; + + for (PLIST_ENTRY lunEntry = bus->LunsListHead.Flink; + lunEntry != &bus->LunsListHead; + lunEntry = lunEntry->Flink) { - DPRINT("(Bus %lu Target %lu Lun %lu)\n", - Bus, LunInfo->TargetId, LunInfo->Lun); + PSCSI_PORT_LUN_EXTENSION lunExt = + CONTAINING_RECORD(lunEntry, SCSI_PORT_LUN_EXTENSION, LunEntry); + + DPRINT("(Bus %lu Target %lu Lun %lu)\n", pathId, lunExt->TargetId, lunExt->Lun); /* Fill InquiryData with values */ - InquiryData->PathId = LunInfo->PathId; - InquiryData->TargetId = LunInfo->TargetId; - InquiryData->Lun = LunInfo->Lun; + InquiryData->PathId = lunExt->PathId; + InquiryData->TargetId = lunExt->TargetId; + InquiryData->Lun = lunExt->Lun; InquiryData->InquiryDataLength = INQUIRYDATABUFFERSIZE; - InquiryData->DeviceClaimed = LunInfo->DeviceClaimed; + InquiryData->DeviceClaimed = lunExt->DeviceClaimed; InquiryData->NextInquiryDataOffset = (ULONG)((PUCHAR)InquiryData + InquiryDataSize - Buffer); /* Copy data in it */ RtlCopyMemory(InquiryData->InquiryData, - LunInfo->InquiryData, + &lunExt->InquiryData, INQUIRYDATABUFFERSIZE); /* Move to the next LUN */ - LunInfo = LunInfo->Next; - InquiryData = (PSCSI_INQUIRY_DATA) ((PCHAR)InquiryData + InquiryDataSize); + InquiryData = (PSCSI_INQUIRY_DATA) ((ULONG_PTR)InquiryData + InquiryDataSize); } /* Either mark the end, or set offset to 0 */ @@ -128,6 +119,269 @@ SpiGetInquiryData( return STATUS_SUCCESS; } +static +UINT32 +GetFieldLength( + _In_ PUCHAR Name, + _In_ UINT32 MaxLength) +{ + UINT32 Index; + UINT32 LastCharacterPosition = 0; + + // scan the field and return last position which contains a valid character + for (Index = 0; Index < MaxLength; Index++) + { + if (Name[Index] != ' ') + { + // trim white spaces from field + LastCharacterPosition = Index; + } + } + + // convert from zero based index to length + return LastCharacterPosition + 1; +} + +static +NTSTATUS +PdoHandleQueryProperty( + _In_ PDEVICE_OBJECT DeviceObject, + _Inout_ PIRP Irp) +{ + PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp); + PSCSI_PORT_LUN_EXTENSION lunExt = DeviceObject->DeviceExtension; + NTSTATUS status; + + ASSERT(ioStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(STORAGE_PROPERTY_QUERY)); + ASSERT(Irp->AssociatedIrp.SystemBuffer); + ASSERT(!lunExt->Common.IsFDO); + + PSTORAGE_PROPERTY_QUERY PropertyQuery = Irp->AssociatedIrp.SystemBuffer; + + // check property type + if (PropertyQuery->PropertyId != StorageDeviceProperty && + PropertyQuery->PropertyId != StorageAdapterProperty) + { + // only device property / adapter property are supported + status = STATUS_INVALID_PARAMETER_1; + goto completeIrp; + } + + // check query type + if (PropertyQuery->QueryType == PropertyExistsQuery) + { + // device property / adapter property is supported + status = STATUS_SUCCESS; + goto completeIrp; + } + + if (PropertyQuery->QueryType != PropertyStandardQuery) + { + // only standard query and exists query are supported + status = STATUS_INVALID_PARAMETER_2; + goto completeIrp; + } + + switch (PropertyQuery->PropertyId) + { + case StorageDeviceProperty: + { + PINQUIRYDATA inquiryData = &lunExt->InquiryData; + + // compute extra parameters length + UINT32 FieldLengthVendor = GetFieldLength(inquiryData->VendorId, 8), + FieldLengthProduct = GetFieldLength(inquiryData->ProductId, 16), + FieldLengthRevision = GetFieldLength(inquiryData->ProductRevisionLevel, 4); + + // total length required is sizeof(STORAGE_DEVICE_DESCRIPTOR) + FieldLength + 4 extra null bytes - 1 + // -1 due STORAGE_DEVICE_DESCRIPTOR contains one byte length of parameter data + UINT32 TotalLength = sizeof(STORAGE_DEVICE_DESCRIPTOR) + + FieldLengthVendor + + FieldLengthProduct + + FieldLengthRevision + + 3; + + // check if output buffer is long enough + if (ioStack->Parameters.DeviceIoControl.OutputBufferLength < TotalLength) + { + // buffer too small + PSTORAGE_DESCRIPTOR_HEADER DescriptorHeader = Irp->AssociatedIrp.SystemBuffer; + ASSERT(ioStack->Parameters.DeviceIoControl.OutputBufferLength >= + sizeof(STORAGE_DESCRIPTOR_HEADER)); + + // return required size + DescriptorHeader->Version = TotalLength; + DescriptorHeader->Size = TotalLength; + + Irp->IoStatus.Information = sizeof(STORAGE_DESCRIPTOR_HEADER); + status = STATUS_SUCCESS; + goto completeIrp; + } + + // initialize the device descriptor + PSTORAGE_DEVICE_DESCRIPTOR deviceDescriptor = Irp->AssociatedIrp.SystemBuffer; + + deviceDescriptor->Version = sizeof(STORAGE_DEVICE_DESCRIPTOR); + deviceDescriptor->Size = TotalLength; + deviceDescriptor->DeviceType = inquiryData->DeviceType; + deviceDescriptor->DeviceTypeModifier = inquiryData->DeviceTypeModifier; + deviceDescriptor->RemovableMedia = inquiryData->RemovableMedia; + deviceDescriptor->CommandQueueing = inquiryData->CommandQueue; + deviceDescriptor->BusType = BusTypeScsi; + deviceDescriptor->VendorIdOffset = + FIELD_OFFSET(STORAGE_DEVICE_DESCRIPTOR, RawDeviceProperties); + deviceDescriptor->ProductIdOffset = + deviceDescriptor->VendorIdOffset + FieldLengthVendor + 1; + deviceDescriptor->ProductRevisionOffset = + deviceDescriptor->ProductIdOffset + FieldLengthProduct + 1; + deviceDescriptor->SerialNumberOffset = 0; + deviceDescriptor->RawPropertiesLength = + FieldLengthVendor + FieldLengthProduct + FieldLengthRevision + 3; + + // copy descriptors + PUCHAR Buffer = deviceDescriptor->RawDeviceProperties; + + RtlCopyMemory(Buffer, inquiryData->VendorId, FieldLengthVendor); + Buffer[FieldLengthVendor] = '\0'; + Buffer += FieldLengthVendor + 1; + + RtlCopyMemory(Buffer, inquiryData->ProductId, FieldLengthProduct); + Buffer[FieldLengthProduct] = '\0'; + Buffer += FieldLengthProduct + 1; + + RtlCopyMemory(Buffer, inquiryData->ProductRevisionLevel, FieldLengthRevision); + Buffer[FieldLengthRevision] = '\0'; + Buffer += FieldLengthRevision + 1; + + DPRINT("Vendor %s\n", + (LPCSTR)((ULONG_PTR)deviceDescriptor + deviceDescriptor->VendorIdOffset)); + DPRINT("Product %s\n", + (LPCSTR)((ULONG_PTR)deviceDescriptor + deviceDescriptor->ProductIdOffset)); + DPRINT("Revision %s\n", + (LPCSTR)((ULONG_PTR)deviceDescriptor + deviceDescriptor->ProductRevisionOffset)); + + Irp->IoStatus.Information = TotalLength; + status = STATUS_SUCCESS; + goto completeIrp; + } + case StorageAdapterProperty: + { + // forward to the lower device + IoSkipCurrentIrpStackLocation(Irp); + return IoCallDriver(lunExt->Common.LowerDevice, Irp); + } + case StorageDeviceIdProperty: + { + // TODO + } + default: + { + UNREACHABLE; + status = STATUS_NOT_IMPLEMENTED; + goto completeIrp; + } + } + +completeIrp: + Irp->IoStatus.Status = status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return status; +} + +static +NTSTATUS +FdoHandleQueryProperty( + _In_ PDEVICE_OBJECT DeviceObject, + _Inout_ PIRP Irp) +{ + PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp); + PSCSI_PORT_DEVICE_EXTENSION portExt = DeviceObject->DeviceExtension; + NTSTATUS status; + + ASSERT(ioStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(STORAGE_PROPERTY_QUERY)); + ASSERT(Irp->AssociatedIrp.SystemBuffer); + ASSERT(portExt->Common.IsFDO); + + PSTORAGE_PROPERTY_QUERY PropertyQuery = Irp->AssociatedIrp.SystemBuffer; + + // check property type (handle only StorageAdapterProperty) + if (PropertyQuery->PropertyId != StorageAdapterProperty) + { + if (PropertyQuery->PropertyId == StorageDeviceProperty || + PropertyQuery->PropertyId == StorageDeviceIdProperty) + { + status = STATUS_INVALID_DEVICE_REQUEST; + } + else + { + status = STATUS_INVALID_PARAMETER_1; + } + + goto completeIrp; + } + + // check query type + if (PropertyQuery->QueryType == PropertyExistsQuery) + { + // device property / adapter property is supported + status = STATUS_SUCCESS; + goto completeIrp; + } + + if (PropertyQuery->QueryType != PropertyStandardQuery) + { + // only standard query and exists query are supported + status = STATUS_INVALID_PARAMETER_2; + goto completeIrp; + } + + if (ioStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(STORAGE_ADAPTER_DESCRIPTOR)) + { + // buffer too small + PSTORAGE_DESCRIPTOR_HEADER DescriptorHeader = Irp->AssociatedIrp.SystemBuffer; + ASSERT(ioStack->Parameters.DeviceIoControl.OutputBufferLength + >= sizeof(STORAGE_DESCRIPTOR_HEADER)); + + // return required size + DescriptorHeader->Version = sizeof(STORAGE_ADAPTER_DESCRIPTOR); + DescriptorHeader->Size = sizeof(STORAGE_ADAPTER_DESCRIPTOR); + + Irp->IoStatus.Information = sizeof(STORAGE_DESCRIPTOR_HEADER); + status = STATUS_SUCCESS; + goto completeIrp; + } + + // get adapter descriptor, information is returned in the same buffer + PSTORAGE_ADAPTER_DESCRIPTOR adapterDescriptor = Irp->AssociatedIrp.SystemBuffer; + + // fill out descriptor + // NOTE: STORAGE_ADAPTER_DESCRIPTOR may vary in size, so it's important to zero out + // all unused fields + *adapterDescriptor = (STORAGE_ADAPTER_DESCRIPTOR) { + .Version = sizeof(STORAGE_ADAPTER_DESCRIPTOR), + .Size = sizeof(STORAGE_ADAPTER_DESCRIPTOR), + .MaximumTransferLength = portExt->PortCapabilities.MaximumTransferLength, + .MaximumPhysicalPages = portExt->PortCapabilities.MaximumPhysicalPages, + .AlignmentMask = portExt->PortCapabilities.AlignmentMask, + .AdapterUsesPio = portExt->PortCapabilities.AdapterUsesPio, + .AdapterScansDown = portExt->PortCapabilities.AdapterScansDown, + .CommandQueueing = portExt->PortCapabilities.TaggedQueuing, + .AcceleratedTransfer = TRUE, + .BusType = BusTypeScsi, // FIXME + .BusMajorVersion = 2, + .BusMinorVersion = 0 + }; + + // store returned length + Irp->IoStatus.Information = sizeof(STORAGE_ADAPTER_DESCRIPTOR); + status = STATUS_SUCCESS; + +completeIrp: + Irp->IoStatus.Status = status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return status; +} + /********************************************************************** * NAME INTERNAL * ScsiPortDeviceControl @@ -152,104 +406,147 @@ ScsiPortDeviceControl( _In_ PIRP Irp) { PIO_STACK_LOCATION Stack; - PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; - PDUMP_POINTERS DumpPointers; - NTSTATUS Status; + PSCSI_PORT_COMMON_EXTENSION comExt = DeviceObject->DeviceExtension; + PSCSI_PORT_DEVICE_EXTENSION portExt; + PSCSI_PORT_LUN_EXTENSION lunExt; + NTSTATUS status; DPRINT("ScsiPortDeviceControl()\n"); Irp->IoStatus.Information = 0; Stack = IoGetCurrentIrpStackLocation(Irp); - DeviceExtension = DeviceObject->DeviceExtension; switch (Stack->Parameters.DeviceIoControl.IoControlCode) { - case IOCTL_SCSI_GET_DUMP_POINTERS: - DPRINT(" IOCTL_SCSI_GET_DUMP_POINTERS\n"); - - if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DUMP_POINTERS)) + case IOCTL_STORAGE_QUERY_PROPERTY: { - Status = STATUS_BUFFER_OVERFLOW; - Irp->IoStatus.Information = sizeof(DUMP_POINTERS); - break; - } + DPRINT(" IOCTL_STORAGE_QUERY_PROPERTY\n"); - DumpPointers = Irp->AssociatedIrp.SystemBuffer; - DumpPointers->DeviceObject = DeviceObject; - /* More data.. ? */ - - Status = STATUS_SUCCESS; - Irp->IoStatus.Information = sizeof(DUMP_POINTERS); - break; - - case IOCTL_SCSI_GET_CAPABILITIES: - DPRINT(" IOCTL_SCSI_GET_CAPABILITIES\n"); - if (Stack->Parameters.DeviceIoControl.OutputBufferLength == sizeof(PVOID)) - { - *((PVOID *)Irp->AssociatedIrp.SystemBuffer) = &DeviceExtension->PortCapabilities; - - Irp->IoStatus.Information = sizeof(PVOID); - Status = STATUS_SUCCESS; - break; - } - - if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(IO_SCSI_CAPABILITIES)) - { - Status = STATUS_BUFFER_TOO_SMALL; - break; - } - - RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, - &DeviceExtension->PortCapabilities, - sizeof(IO_SCSI_CAPABILITIES)); - - Irp->IoStatus.Information = sizeof(IO_SCSI_CAPABILITIES); - Status = STATUS_SUCCESS; - break; - - case IOCTL_SCSI_GET_INQUIRY_DATA: - DPRINT(" IOCTL_SCSI_GET_INQUIRY_DATA\n"); - - /* Copy inquiry data to the port device extension */ - Status = SpiGetInquiryData(DeviceExtension, Irp); - break; - - case IOCTL_SCSI_MINIPORT: - DPRINT1("IOCTL_SCSI_MINIPORT unimplemented!\n"); - Status = STATUS_NOT_IMPLEMENTED; - break; - - case IOCTL_SCSI_PASS_THROUGH: - DPRINT1("IOCTL_SCSI_PASS_THROUGH unimplemented!\n"); - Status = STATUS_NOT_IMPLEMENTED; - break; - - default: - if (DEVICE_TYPE_FROM_CTL_CODE(Stack->Parameters.DeviceIoControl.IoControlCode) == MOUNTDEVCONTROLTYPE) - { - switch (Stack->Parameters.DeviceIoControl.IoControlCode) + if (!VerifyIrpInBufferSize(Irp, sizeof(STORAGE_PROPERTY_QUERY))) { - case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME: - DPRINT1("Got unexpected IOCTL_MOUNTDEV_QUERY_DEVICE_NAME\n"); - break; - case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID: - DPRINT1("Got unexpected IOCTL_MOUNTDEV_QUERY_UNIQUE_ID\n"); - break; - default: - DPRINT(" got ioctl intended for the mount manager: 0x%lX\n", Stack->Parameters.DeviceIoControl.IoControlCode); + status = STATUS_BUFFER_TOO_SMALL; break; } - } else { - DPRINT1(" unknown ioctl code: 0x%lX\n", Stack->Parameters.DeviceIoControl.IoControlCode); - } - Status = STATUS_NOT_IMPLEMENTED; - break; + + if (comExt->IsFDO) + return FdoHandleQueryProperty(DeviceObject, Irp); + else + return PdoHandleQueryProperty(DeviceObject, Irp); + } + case IOCTL_SCSI_GET_ADDRESS: + { + DPRINT(" IOCTL_SCSI_GET_ADDRESS\n"); + + if (comExt->IsFDO) + { + status = STATUS_INVALID_DEVICE_REQUEST; + break; + } + + PSCSI_ADDRESS address = Irp->AssociatedIrp.SystemBuffer; + if (!VerifyIrpOutBufferSize(Irp, sizeof(*address))) + { + status = STATUS_BUFFER_TOO_SMALL; + break; + } + + lunExt = DeviceObject->DeviceExtension; + portExt = comExt->LowerDevice->DeviceExtension; + + address->Length = sizeof(SCSI_ADDRESS); + address->PortNumber = portExt->PortNumber; + address->PathId = lunExt->PathId; + address->TargetId = lunExt->TargetId; + address->Lun = lunExt->Lun; + + Irp->IoStatus.Information = sizeof(SCSI_ADDRESS); + status = STATUS_SUCCESS; + break; + } + case IOCTL_SCSI_GET_DUMP_POINTERS: + { + DPRINT(" IOCTL_SCSI_GET_DUMP_POINTERS\n"); + + if (!comExt->IsFDO) + { + IoSkipCurrentIrpStackLocation(Irp); + return IoCallDriver(comExt->LowerDevice, Irp); + } + + PDUMP_POINTERS dumpPointers = Irp->AssociatedIrp.SystemBuffer; + if (!VerifyIrpOutBufferSize(Irp, sizeof(*dumpPointers))) + { + status = STATUS_BUFFER_TOO_SMALL; + break; + } + + dumpPointers->DeviceObject = DeviceObject; + /* More data.. ? */ + + status = STATUS_SUCCESS; + Irp->IoStatus.Information = sizeof(DUMP_POINTERS); + break; + } + case IOCTL_SCSI_GET_CAPABILITIES: + { + DPRINT(" IOCTL_SCSI_GET_CAPABILITIES\n"); + + if (!comExt->IsFDO) + { + status = STATUS_INVALID_DEVICE_REQUEST; + break; + } + + if (!VerifyIrpOutBufferSize(Irp, sizeof(IO_SCSI_CAPABILITIES))) + { + status = STATUS_BUFFER_TOO_SMALL; + break; + } + + portExt = DeviceObject->DeviceExtension; + + RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, + &portExt->PortCapabilities, + sizeof(IO_SCSI_CAPABILITIES)); + + status = STATUS_SUCCESS; + Irp->IoStatus.Information = sizeof(IO_SCSI_CAPABILITIES); + break; + } + case IOCTL_SCSI_GET_INQUIRY_DATA: + { + DPRINT(" IOCTL_SCSI_GET_INQUIRY_DATA\n"); + + if (!comExt->IsFDO) + { + status = STATUS_INVALID_DEVICE_REQUEST; + break; + } + + /* Copy inquiry data to the port device extension */ + status = SpiGetInquiryData(DeviceObject->DeviceExtension, Irp); + break; + } + case IOCTL_SCSI_MINIPORT: + DPRINT1("IOCTL_SCSI_MINIPORT unimplemented!\n"); + status = STATUS_NOT_IMPLEMENTED; + break; + + case IOCTL_SCSI_PASS_THROUGH: + DPRINT1("IOCTL_SCSI_PASS_THROUGH unimplemented!\n"); + status = STATUS_NOT_IMPLEMENTED; + break; + + default: + DPRINT1("unknown ioctl code: 0x%lX\n", Stack->Parameters.DeviceIoControl.IoControlCode); + status = STATUS_NOT_SUPPORTED; + break; } /* Complete the request with the given status */ - Irp->IoStatus.Status = Status; + Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT); - return Status; + return status; } diff --git a/drivers/storage/port/scsiport/pdo.c b/drivers/storage/port/scsiport/pdo.c index 7365f42e443..182f2b029ec 100644 --- a/drivers/storage/port/scsiport/pdo.c +++ b/drivers/storage/port/scsiport/pdo.c @@ -4,40 +4,48 @@ * PURPOSE: Logical Unit (PDO) functions * COPYRIGHT: Eric Kohl (eric.kohl@reactos.org) * Aleksey Bragin (aleksey@reactos.org) + * 2020 Victor Perevertkin (victor.perevertkin@reactos.org) */ #include "scsiport.h" +#include "scsitypes.h" #define NDEBUG #include -PSCSI_PORT_LUN_EXTENSION -SpiAllocateLunExtension( +PDEVICE_OBJECT +PdoCreateLunDevice( _In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension) { PSCSI_PORT_LUN_EXTENSION LunExtension; - ULONG LunExtensionSize; + PDEVICE_OBJECT LunPDO; - DPRINT("SpiAllocateLunExtension(%p)\n", DeviceExtension); + ULONG LunExtensionSize = DeviceExtension->LunExtensionSize + sizeof(SCSI_PORT_LUN_EXTENSION); - /* Round LunExtensionSize first to the sizeof LONGLONG */ - LunExtensionSize = (DeviceExtension->LunExtensionSize + - sizeof(LONGLONG) - 1) & ~(sizeof(LONGLONG) - 1); + NTSTATUS Status = IoCreateDevice(DeviceExtension->Common.DeviceObject->DriverObject, + LunExtensionSize, + NULL, + FILE_DEVICE_DISK, + FILE_AUTOGENERATED_DEVICE_NAME | FILE_DEVICE_SECURE_OPEN, + FALSE, + &LunPDO); - LunExtensionSize += sizeof(SCSI_PORT_LUN_EXTENSION); - DPRINT("LunExtensionSize %lu\n", LunExtensionSize); - - LunExtension = ExAllocatePoolWithTag(NonPagedPool, LunExtensionSize, TAG_SCSIPORT); - if (LunExtension == NULL) + if (!NT_SUCCESS(Status)) { - DPRINT1("Out of resources!\n"); + DPRINT1("Failed to create a Lun PDO, status: %x\n", Status); return NULL; } + LunExtension = LunPDO->DeviceExtension; + /* Zero everything */ RtlZeroMemory(LunExtension, LunExtensionSize); + LunExtension->Common.IsFDO = FALSE; + LunExtension->Common.DeviceObject = LunPDO; + LunExtension->Common.LowerDevice = DeviceExtension->Common.DeviceObject; + /* Initialize a list of requests */ InitializeListHead(&LunExtension->SrbInfo.Requests); @@ -50,66 +58,54 @@ SpiAllocateLunExtension( /* Initialize request queue */ KeInitializeDeviceQueue(&LunExtension->DeviceQueue); - return LunExtension; + LunPDO->Flags |= DO_DIRECT_IO; + LunPDO->Flags &= ~DO_DEVICE_INITIALIZING; + + return LunPDO; } PSCSI_PORT_LUN_EXTENSION -SpiGetLunExtension( +GetLunByPath( _In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, _In_ UCHAR PathId, _In_ UCHAR TargetId, _In_ UCHAR Lun) { - PSCSI_PORT_LUN_EXTENSION LunExtension; - - DPRINT("SpiGetLunExtension(%p %u %u %u) called\n", - DeviceExtension, PathId, TargetId, Lun); - - /* Get appropriate list */ - LunExtension = DeviceExtension->LunExtensionList[(TargetId + Lun) % LUS_NUMBER]; - - /* Iterate it until we find what we need */ - while (LunExtension) + if (PathId >= DeviceExtension->NumberOfBuses) { - if (LunExtension->TargetId == TargetId && - LunExtension->Lun == Lun && - LunExtension->PathId == PathId) - { - /* All matches, return */ - return LunExtension; - } - - /* Advance to the next item */ - LunExtension = LunExtension->Next; + DPRINT1("Invalid PathId: %u\n", PathId); + return NULL; } - /* We did not find anything */ - DPRINT("Nothing found\n"); + PSCSI_BUS_INFO bus = &DeviceExtension->Buses[PathId]; + + for (PLIST_ENTRY lunEntry = bus->LunsListHead.Flink; + lunEntry != &bus->LunsListHead; + lunEntry = lunEntry->Flink) + { + PSCSI_PORT_LUN_EXTENSION lunExt = + CONTAINING_RECORD(lunEntry, SCSI_PORT_LUN_EXTENSION, LunEntry); + + if (lunExt->PathId == PathId && + lunExt->TargetId == TargetId && + lunExt->Lun == Lun) + { + return lunExt; + } + } + + DPRINT("SCSI LUN (%u, %u, %u) was not found\n", PathId, TargetId, Lun); return NULL; } PSCSI_REQUEST_BLOCK_INFO SpiGetSrbData( _In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, - _In_ UCHAR PathId, - _In_ UCHAR TargetId, - _In_ UCHAR Lun, + _In_ PSCSI_PORT_LUN_EXTENSION LunExtension, _In_ UCHAR QueueTag) { - PSCSI_PORT_LUN_EXTENSION LunExtension; - if (QueueTag == SP_UNTAGGED) { - /* Untagged request, get LU and return pointer to SrbInfo */ - LunExtension = SpiGetLunExtension(DeviceExtension, - PathId, - TargetId, - Lun); - - /* Return NULL in case of error */ - if (!LunExtension) - return(NULL); - /* Return the pointer to SrbInfo */ return &LunExtension->SrbInfo; } @@ -122,3 +118,506 @@ SpiGetSrbData( return &DeviceExtension->SrbInfo[QueueTag -1]; } } + +static +ULONG +CopyField( + IN PUCHAR Name, + IN PCHAR Buffer, + IN ULONG MaxLength) +{ + ULONG Index; + + for (Index = 0; Index < MaxLength; Index++) + { + if (Name[Index] <= ' ' || Name[Index] >= 0x7F /* last printable ascii character */ || Name[Index] == ',') + { + // convert to underscore + Buffer[Index] = '_'; + } + else + { + // just copy character + Buffer[Index] = Name[Index]; + } + } + + return MaxLength; +} + +static +ULONG +CopyFieldTruncate( + IN PUCHAR Name, + IN PCHAR Buffer, + IN ULONG MaxLength) +{ + ULONG Index; + + for (Index = 0; Index < MaxLength; Index++) + { + if (Name[Index] == '\0') + { + break; + } + else if (Name[Index] <= ' ' || Name[Index] >= 0x7F /* last printable ascii character */ || Name[Index] == ',') + { + // convert to space + Buffer[Index] = ' '; + } + else + { + // just copy character + Buffer[Index] = Name[Index]; + } + } + + return Index; +} + +static +NTSTATUS +PdoHandleQueryDeviceText( + _In_ PDEVICE_OBJECT DeviceObject, + _Inout_ PIRP Irp) +{ + PSCSI_PORT_LUN_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; + PIO_STACK_LOCATION IoStack; + UINT32 Offset = 0; + PINQUIRYDATA InquiryData; + CHAR LocalBuffer[sizeof(InquiryData->VendorId) + sizeof(InquiryData->ProductId) + 2]; + ANSI_STRING AnsiString; + UNICODE_STRING DeviceDescription; + + IoStack = IoGetCurrentIrpStackLocation(Irp); + + InquiryData = &DeviceExtension->InquiryData; + + switch (IoStack->Parameters.QueryDeviceText.DeviceTextType) + { + case DeviceTextDescription: + case DeviceTextLocationInformation: + { + DPRINT("PdoHandleQueryDeviceText\n"); + + Offset += CopyFieldTruncate(InquiryData->VendorId, + &LocalBuffer[Offset], + sizeof(InquiryData->VendorId)); + LocalBuffer[Offset++] = ' '; + Offset += CopyFieldTruncate(InquiryData->ProductId, + &LocalBuffer[Offset], + sizeof(InquiryData->ProductId)); + LocalBuffer[Offset++] = '\0'; + + RtlInitAnsiString(&AnsiString, (PCSZ)&LocalBuffer); + + DeviceDescription.Length = 0; + DeviceDescription.MaximumLength = (USHORT)(Offset * sizeof(WCHAR)); + DeviceDescription.Buffer = ExAllocatePoolWithTag(PagedPool, + DeviceDescription.MaximumLength, + TAG_SCSIPORT); + if (!DeviceDescription.Buffer) + { + Irp->IoStatus.Information = 0; + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlAnsiStringToUnicodeString(&DeviceDescription, &AnsiString, FALSE); + + Irp->IoStatus.Information = (ULONG_PTR)DeviceDescription.Buffer; + return STATUS_SUCCESS; + } + default: + { + Irp->IoStatus.Information = 0; + return Irp->IoStatus.Status; + } + } +} + +static +NTSTATUS +PdoHandleQueryDeviceId( + _In_ PDEVICE_OBJECT DeviceObject, + _Inout_ PIRP Irp) +{ + PSCSI_PORT_LUN_EXTENSION DeviceExtension; + NTSTATUS Status; + CHAR Buffer[100] = {0}; + LPCSTR DeviceType; + ULONG Offset = 0; + PINQUIRYDATA InquiryData; + ANSI_STRING AnsiString; + UNICODE_STRING DeviceId; + + DeviceExtension = DeviceObject->DeviceExtension; + InquiryData = &DeviceExtension->InquiryData; + + DeviceType = GetDeviceType(InquiryData); + + // lets create device string + Offset = sprintf(&Buffer[Offset], "SCSI\\"); + Offset += sprintf(&Buffer[Offset], DeviceType); + Offset += sprintf(&Buffer[Offset], "&Ven_"); + Offset += CopyField(InquiryData->VendorId, &Buffer[Offset], 8); + Offset += sprintf(&Buffer[Offset], "&Prod_"); + Offset += CopyField(InquiryData->ProductId, &Buffer[Offset], 16); + Offset += sprintf(&Buffer[Offset], "&Rev_"); + Offset += CopyField(InquiryData->ProductRevisionLevel, &Buffer[Offset], 4); + + RtlInitAnsiString(&AnsiString, (PCSZ)Buffer); + + // allocate DeviceId string + Status = RtlAnsiStringToUnicodeString(&DeviceId, &AnsiString, TRUE); + + if (NT_SUCCESS(Status)) + { + Irp->IoStatus.Information = (ULONG_PTR)DeviceId.Buffer; + } + + DPRINT("DeviceId %wZ Status %x\n", &DeviceId, Status); + + return Status; +} + +static +VOID +ConvertToUnicodeString( + IN CHAR * Buffer, + IN ULONG ResultBufferLength, + IN ULONG ResultBufferOffset, + OUT LPWSTR ResultBuffer, + OUT PULONG NewResultBufferOffset) +{ + UNICODE_STRING DeviceString; + ANSI_STRING AnsiString; + NTSTATUS Status; + + ASSERT(ResultBufferLength); + ASSERT(ResultBufferLength > ResultBufferOffset); + + DPRINT("ResultBufferOffset %lu ResultBufferLength %lu Buffer %s Length %lu\n", + ResultBufferOffset, ResultBufferLength, Buffer, strlen(Buffer)); + + // construct destination string + DeviceString.Buffer = &ResultBuffer[ResultBufferOffset]; + DeviceString.Length = 0; + DeviceString.MaximumLength = (ResultBufferLength - ResultBufferOffset) * sizeof(WCHAR); + + // initialize source string + RtlInitAnsiString(&AnsiString, Buffer); + + Status = RtlAnsiStringToUnicodeString(&DeviceString, &AnsiString, FALSE); + ASSERT(Status == STATUS_SUCCESS); + + // subtract consumed bytes + ResultBufferLength -= (DeviceString.Length + sizeof(WCHAR)) / sizeof(WCHAR); + ResultBufferOffset += (DeviceString.Length + sizeof(WCHAR)) / sizeof(WCHAR); + + *NewResultBufferOffset = ResultBufferOffset; +} + +static +NTSTATUS +PdoHandleQueryHardwareId( + _In_ PDEVICE_OBJECT DeviceObject, + _Inout_ PIRP Irp) +{ + PSCSI_PORT_LUN_EXTENSION PDODeviceExtension = DeviceObject->DeviceExtension; + LPCSTR GenericType, DeviceType; + LPWSTR Buffer; + CHAR Id1[50], Id2[50], Id3[50], Id4[50], Id5[50], Id6[50], Id7[50]; + ULONG Id1Length, Id2Length, Id3Length, Id4Length, Id5Length, Id6Length, Id7Length; + ULONG Offset, TotalLength, Length; + PINQUIRYDATA InquiryData; + + InquiryData = &PDODeviceExtension->InquiryData; + + DeviceType = GetDeviceType(InquiryData); + GenericType = GetGenericType(InquiryData); + + ASSERT(GenericType); + + // generate id 1 + // SCSI\SCSIType_VendorId(8)_ProductId(16)_Revision(4) + RtlZeroMemory(Id1, sizeof(Id1)); + Offset = 0; + Offset = sprintf(&Id1[Offset], "SCSI\\"); + Offset += sprintf(&Id1[Offset], DeviceType); + Offset += CopyField(InquiryData->VendorId, &Id1[Offset], 8); + Offset += CopyField(InquiryData->ProductId, &Id1[Offset], 16); + Offset += CopyField(InquiryData->ProductRevisionLevel, &Id1[Offset], 4); + Id1Length = strlen(Id1) + 1; + DPRINT("PdoHandleQueryHardwareId HardwareId1 %s\n", Id1); + + // generate id 2 + // SCSI\SCSIType_VendorId(8)_ProductId(16) + RtlZeroMemory(Id2, sizeof(Id2)); + Offset = 0; + Offset = sprintf(&Id2[Offset], "SCSI\\"); + Offset += sprintf(&Id2[Offset], DeviceType); + Offset += CopyField(InquiryData->VendorId, &Id2[Offset], 8); + Offset += CopyField(InquiryData->ProductId, &Id2[Offset], 16); + Id2Length = strlen(Id2) + 1; + DPRINT("PdoHandleQueryHardwareId HardwareId2 %s\n", Id2); + + // generate id 3 + // SCSI\SCSIType_VendorId(8) + RtlZeroMemory(Id3, sizeof(Id3)); + Offset = 0; + Offset = sprintf(&Id3[Offset], "SCSI\\"); + Offset += sprintf(&Id3[Offset], DeviceType); + Offset += CopyField(InquiryData->VendorId, &Id3[Offset], 8); + Id3Length = strlen(Id3) + 1; + DPRINT("PdoHandleQueryHardwareId HardwareId3 %s\n", Id3); + + // generate id 4 + // SCSI\SCSIType_VendorId(8)_ProductId(16)_Revision(1) + RtlZeroMemory(Id4, sizeof(Id4)); + Offset = 0; + Offset = sprintf(&Id4[Offset], "SCSI\\"); + Offset += sprintf(&Id4[Offset], DeviceType); + Offset += CopyField(InquiryData->VendorId, &Id4[Offset], 8); + Offset += CopyField(InquiryData->ProductId, &Id4[Offset], 16); + Offset += CopyField(InquiryData->ProductRevisionLevel, &Id4[Offset], 1); + Id4Length = strlen(Id4) + 1; + DPRINT("PdoHandleQueryHardwareId HardwareId4 %s\n", Id4); + + // generate id 5 + // SCSIType_VendorId(8)_ProductId(16)_Revision(1) + RtlZeroMemory(Id5, sizeof(Id5)); + Offset = 0; + Offset = sprintf(&Id5[Offset], DeviceType); + Offset += CopyField(InquiryData->VendorId, &Id5[Offset], 8); + Offset += CopyField(InquiryData->ProductId, &Id5[Offset], 16); + Offset += CopyField(InquiryData->ProductRevisionLevel, &Id5[Offset], 1); + Id5Length = strlen(Id5) + 1; + DPRINT("PdoHandleQueryHardwareId HardwareId5 %s\n", Id5); + + // generate id 6 + // SCSI\SCSIType + RtlZeroMemory(Id6, sizeof(Id6)); + Offset = 0; + Offset = sprintf(&Id6[Offset], "SCSI\\"); + Offset += sprintf(&Id6[Offset], GenericType); + Id6Length = strlen(Id6) + 1; + DPRINT("PdoHandleQueryHardwareId HardwareId6 %s\n", Id6); + + // generate id 7 + // SCSIType + RtlZeroMemory(Id7, sizeof(Id7)); + Offset = 0; + Offset = sprintf(&Id7[Offset], GenericType); + Id7Length = strlen(Id7) + 1; + DPRINT("PdoHandleQueryHardwareId HardwareId7 %s\n", Id7); + + TotalLength = Id1Length + Id2Length + Id3Length + Id4Length + Id5Length + Id6Length + Id7Length + 1; + + Buffer = ExAllocatePoolWithTag(PagedPool, TotalLength * sizeof(WCHAR), TAG_SCSIPORT); + if (!Buffer) + { + Irp->IoStatus.Information = 0; + return STATUS_INSUFFICIENT_RESOURCES; + } + + // reset offset + Offset = 0; + Length = TotalLength; + + ConvertToUnicodeString(Id1, Length, Offset, Buffer, &Offset); + ConvertToUnicodeString(Id2, Length, Offset, Buffer, &Offset); + ConvertToUnicodeString(Id3, Length, Offset, Buffer, &Offset); + ConvertToUnicodeString(Id4, Length, Offset, Buffer, &Offset); + ConvertToUnicodeString(Id5, Length, Offset, Buffer, &Offset); + ConvertToUnicodeString(Id6, Length, Offset, Buffer, &Offset); + ConvertToUnicodeString(Id7, Length, Offset, Buffer, &Offset); + + Buffer[Offset] = UNICODE_NULL; + + ASSERT(Offset + 1 == Length); + + Irp->IoStatus.Information = (ULONG_PTR)Buffer; + return STATUS_SUCCESS; +} + +static +NTSTATUS +PdoHandleQueryCompatibleId( + _In_ PDEVICE_OBJECT DeviceObject, + _Inout_ PIRP Irp) +{ + PSCSI_PORT_LUN_EXTENSION PDODeviceExtension = DeviceObject->DeviceExtension; + CHAR Buffer[100] = {0}; + ULONG Length, Offset; + LPWSTR InstanceId; + LPCSTR DeviceType; + + DeviceType = GetDeviceType(&PDODeviceExtension->InquiryData); + + // format instance id + Length = sprintf(Buffer, "%s", DeviceType) + 1; + Length += sprintf(&Buffer[Length], "%s", "RAW") + 2; + + InstanceId = ExAllocatePoolWithTag(PagedPool, Length * sizeof(WCHAR), TAG_SCSIPORT); + if (!InstanceId) + { + Irp->IoStatus.Information = 0; + return STATUS_INSUFFICIENT_RESOURCES; + } + + ConvertToUnicodeString(Buffer, Length, 0, InstanceId, &Offset); + ConvertToUnicodeString(&Buffer[Offset], Length, Offset, InstanceId, &Offset); + + InstanceId[Offset] = UNICODE_NULL; + + DPRINT("PdoHandleQueryCompatibleId %S\n", InstanceId); + + Irp->IoStatus.Information = (ULONG_PTR)InstanceId; + return STATUS_SUCCESS; +} + +static +NTSTATUS +PdoHandleQueryInstanceId( + _In_ PDEVICE_OBJECT DeviceObject, + _Inout_ PIRP Irp) +{ + PSCSI_PORT_LUN_EXTENSION lunExt = DeviceObject->DeviceExtension; + WCHAR Buffer[26]; + ULONG Length; + LPWSTR InstanceId; + + // use instance count and LUN + swprintf(Buffer, L"%x%x%x", lunExt->PathId, lunExt->TargetId, lunExt->Lun); + + Length = wcslen(Buffer) + 1; + + InstanceId = ExAllocatePoolWithTag(PagedPool, Length * sizeof(WCHAR), TAG_SCSIPORT); + if (!InstanceId) + { + Irp->IoStatus.Information = 0; + return STATUS_INSUFFICIENT_RESOURCES; + } + + wcscpy(InstanceId, Buffer); + + DPRINT("PdoHandleQueryInstanceId %S\n", InstanceId); + + Irp->IoStatus.Information = (ULONG_PTR)InstanceId; + return STATUS_SUCCESS; +} + +static +NTSTATUS +PdoHandleDeviceRelations( + _In_ PDEVICE_OBJECT DeviceObject, + _Inout_ PIRP Irp) +{ + PDEVICE_RELATIONS deviceRelations; + PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp); + + // check if relation type is BusRelations + if (ioStack->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation) + { + // PDO handles only target device relation + return Irp->IoStatus.Status; + } + + deviceRelations = ExAllocatePoolWithTag(PagedPool, sizeof(DEVICE_RELATIONS), TAG_SCSIPORT); + if (!deviceRelations) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + // initialize device relations + deviceRelations->Count = 1; + deviceRelations->Objects[0] = DeviceObject; + ObReferenceObject(DeviceObject); + + Irp->IoStatus.Information = (ULONG_PTR)deviceRelations; + return STATUS_SUCCESS; +} + +NTSTATUS +PdoDispatchPnp( + _In_ PDEVICE_OBJECT DeviceObject, + _Inout_ PIRP Irp) +{ + PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp); + PSCSI_PORT_LUN_EXTENSION lunExt = DeviceObject->DeviceExtension; + NTSTATUS status; + + DPRINT("PDO PnP request %s\n", GetIRPMinorFunctionString(ioStack->MinorFunction)); + + ASSERT(!lunExt->Common.IsFDO); + + switch (ioStack->MinorFunction) + { + case IRP_MN_START_DEVICE: + { + RegistryInitLunKey(lunExt); + status = STATUS_SUCCESS; + break; + } + case IRP_MN_REMOVE_DEVICE: + case IRP_MN_QUERY_CAPABILITIES: + case IRP_MN_QUERY_REMOVE_DEVICE: + case IRP_MN_QUERY_STOP_DEVICE: + case IRP_MN_SURPRISE_REMOVAL: + { + status = STATUS_SUCCESS; + break; + } + case IRP_MN_QUERY_DEVICE_RELATIONS: + { + status = PdoHandleDeviceRelations(DeviceObject, Irp); + break; + } + case IRP_MN_QUERY_DEVICE_TEXT: + { + status = PdoHandleQueryDeviceText(DeviceObject, Irp); + break; + } + case IRP_MN_QUERY_ID: + { + DPRINT("IRP_MN_QUERY_ID IdType %s\n", + DbgGetDeviceIDString(ioStack->Parameters.QueryId.IdType)); + + if (ioStack->Parameters.QueryId.IdType == BusQueryDeviceID) + { + status = PdoHandleQueryDeviceId(DeviceObject, Irp); + break; + } + else if (ioStack->Parameters.QueryId.IdType == BusQueryHardwareIDs) + { + status = PdoHandleQueryHardwareId(DeviceObject, Irp); + break; + } + else if (ioStack->Parameters.QueryId.IdType == BusQueryInstanceID) + { + status = PdoHandleQueryInstanceId(DeviceObject, Irp); + break; + } + else if (ioStack->Parameters.QueryId.IdType == BusQueryCompatibleIDs) + { + status = PdoHandleQueryCompatibleId(DeviceObject, Irp); + break; + } + + // fallthrough + } + default: + { + // do nothing + status = Irp->IoStatus.Status; + } + } + + if (status != STATUS_PENDING) + { + Irp->IoStatus.Status = status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + } + + return status; +} diff --git a/drivers/storage/port/scsiport/power.c b/drivers/storage/port/scsiport/power.c new file mode 100644 index 00000000000..b3c7b4ce89a --- /dev/null +++ b/drivers/storage/port/scsiport/power.c @@ -0,0 +1,41 @@ +/* + * PROJECT: ReactOS Storage Stack / SCSIPORT storage port library + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: PnP power handlers + * COPYRIGHT: Copyright 2016 Thomas Faber + */ + +#include "scsiport.h" + + +NTSTATUS +NTAPI +ScsiPortDispatchPower( + _In_ PDEVICE_OBJECT DeviceObject, + _Inout_ PIRP Irp) +{ + PSCSI_PORT_COMMON_EXTENSION comExt = DeviceObject->DeviceExtension; + + if (comExt->IsFDO) + { + PoStartNextPowerIrp(Irp); + IoSkipCurrentIrpStackLocation(Irp); + return PoCallDriver(comExt->LowerDevice, Irp); + } + else + { + PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp); + switch (ioStack->MinorFunction) + { + case IRP_MN_SET_POWER: + case IRP_MN_QUERY_POWER: + Irp->IoStatus.Status = STATUS_SUCCESS; + break; + } + + NTSTATUS status = Irp->IoStatus.Status; + PoStartNextPowerIrp(Irp); + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return status; + } +} diff --git a/drivers/storage/port/scsiport/registry.c b/drivers/storage/port/scsiport/registry.c index 5deaf85c8e9..3b9e235d752 100644 --- a/drivers/storage/port/scsiport/registry.c +++ b/drivers/storage/port/scsiport/registry.c @@ -4,9 +4,11 @@ * PURPOSE: Registry operations * COPYRIGHT: Eric Kohl (eric.kohl@reactos.org) * Aleksey Bragin (aleksey@reactos.org) + * 2020 Victor Perevertkin (victor.perevertkin@reactos.org) */ #include "scsiport.h" +#include "scsitypes.h" #define NDEBUG #include @@ -15,26 +17,28 @@ VOID SpiInitOpenKeys( _Inout_ PCONFIGURATION_INFO ConfigInfo, - _In_ PUNICODE_STRING RegistryPath) + _In_ PSCSI_PORT_DRIVER_EXTENSION DriverExtension) { OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING KeyName; NTSTATUS Status; + HANDLE parametersKey; + + DriverExtension->IsLegacyDriver = TRUE; /* Open the service key */ InitializeObjectAttributes(&ObjectAttributes, - RegistryPath, - OBJ_CASE_INSENSITIVE, + &DriverExtension->RegistryPath, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); - Status = ZwOpenKey(&ConfigInfo->ServiceKey, - KEY_READ, - &ObjectAttributes); + Status = ZwOpenKey(&ConfigInfo->ServiceKey, KEY_READ, &ObjectAttributes); if (!NT_SUCCESS(Status)) { - DPRINT("Unable to open driver's registry key %wZ, status 0x%08x\n", RegistryPath, Status); + DPRINT("Unable to open driver's registry key %wZ, status 0x%08x\n", + DriverExtension->RegistryPath, Status); ConfigInfo->ServiceKey = NULL; } @@ -44,14 +48,12 @@ SpiInitOpenKeys( RtlInitUnicodeString(&KeyName, L"Parameters"); InitializeObjectAttributes(&ObjectAttributes, &KeyName, - OBJ_CASE_INSENSITIVE, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, ConfigInfo->ServiceKey, - (PSECURITY_DESCRIPTOR) NULL); + NULL); /* Try to open it */ - Status = ZwOpenKey(&ConfigInfo->DeviceKey, - KEY_READ, - &ObjectAttributes); + Status = ZwOpenKey(&ConfigInfo->DeviceKey, KEY_READ, &ObjectAttributes); if (NT_SUCCESS(Status)) { @@ -69,14 +71,32 @@ SpiInitOpenKeys( RtlInitUnicodeString(&KeyName, L"Device"); InitializeObjectAttributes(&ObjectAttributes, &KeyName, - OBJ_CASE_INSENSITIVE, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, ConfigInfo->ServiceKey, NULL); /* We don't check for failure here - not needed */ - ZwOpenKey(&ConfigInfo->DeviceKey, - KEY_READ, - &ObjectAttributes); + ZwOpenKey(&ConfigInfo->DeviceKey, KEY_READ, &ObjectAttributes); + + // Detect the driver PnP capabilities via its Parameters\PnpInterface key + // for example: HKLM\SYSTEM\CurrentControlSet\Services\UNIATA\Parameters\PnpInterface + + RtlInitUnicodeString(&KeyName, L"PnpInterface"); + InitializeObjectAttributes(&ObjectAttributes, + &KeyName, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + ConfigInfo->ServiceKey, + NULL); + + Status = ZwOpenKey(¶metersKey, KEY_READ, &ObjectAttributes); + + if (NT_SUCCESS(Status)) + { + // if the key exists, it's enough for us for now + // (the proper check should iterate over INTERFACE_TYPE values) + DriverExtension->IsLegacyDriver = FALSE; + ZwClose(parametersKey); + } } } @@ -104,34 +124,24 @@ SpiInitOpenKeys( */ NTSTATUS -SpiBuildDeviceMap( - _In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, - _In_ PUNICODE_STRING RegistryPath) +RegistryInitAdapterKey( + _Inout_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension) { - PSCSI_PORT_LUN_EXTENSION LunExtension; OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING KeyName; UNICODE_STRING ValueName; WCHAR NameBuffer[64]; - ULONG Disposition; HANDLE ScsiKey; HANDLE ScsiPortKey = NULL; HANDLE ScsiBusKey = NULL; HANDLE ScsiInitiatorKey = NULL; - HANDLE ScsiTargetKey = NULL; - HANDLE ScsiLunKey = NULL; ULONG BusNumber; - ULONG Target; - ULONG CurrentTarget; - ULONG Lun; - PWCHAR DriverName; ULONG UlongData; - PWCHAR TypeName; NTSTATUS Status; DPRINT("SpiBuildDeviceMap() called\n"); - if (DeviceExtension == NULL || RegistryPath == NULL) + if (DeviceExtension == NULL) { DPRINT1("Invalid parameter\n"); return STATUS_INVALID_PARAMETER; @@ -151,7 +161,7 @@ SpiBuildDeviceMap( 0, NULL, REG_OPTION_VOLATILE, - &Disposition); + NULL); if (!NT_SUCCESS(Status)) { DPRINT("ZwCreateKey() failed (Status %lx)\n", Status); @@ -165,18 +175,14 @@ SpiBuildDeviceMap( L"Scsi Port %lu", DeviceExtension->PortNumber); RtlInitUnicodeString(&KeyName, NameBuffer); - InitializeObjectAttributes(&ObjectAttributes, - &KeyName, - OBJ_KERNEL_HANDLE, - ScsiKey, - NULL); + InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_KERNEL_HANDLE, ScsiKey, NULL); Status = ZwCreateKey(&ScsiPortKey, KEY_ALL_ACCESS, &ObjectAttributes, 0, NULL, REG_OPTION_VOLATILE, - &Disposition); + NULL); ZwClose(ScsiKey); if (!NT_SUCCESS(Status)) { @@ -206,14 +212,29 @@ SpiBuildDeviceMap( } /* Set 'Driver' (REG_SZ) value */ - DriverName = wcsrchr(RegistryPath->Buffer, L'\\') + 1; + PUNICODE_STRING driverNameU = &DeviceExtension->Common.DeviceObject->DriverObject->DriverName; + PWCHAR driverName = ExAllocatePoolWithTag(PagedPool, + driverNameU->Length + sizeof(UNICODE_NULL), + TAG_SCSIPORT); + if (!driverName) + { + DPRINT("Failed to allocate driverName!\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlCopyMemory(driverName, driverNameU->Buffer, driverNameU->Length); + driverName[driverNameU->Length / sizeof(WCHAR)] = UNICODE_NULL; + RtlInitUnicodeString(&ValueName, L"Driver"); Status = ZwSetValueKey(ScsiPortKey, &ValueName, 0, REG_SZ, - DriverName, - (ULONG)((wcslen(DriverName) + 1) * sizeof(WCHAR))); + driverName, + driverNameU->Length + sizeof(UNICODE_NULL)); + + ExFreePoolWithTag(driverName, TAG_SCSIPORT); + if (!NT_SUCCESS(Status)) { DPRINT("ZwSetValueKey('Driver') failed (Status %lx)\n", Status); @@ -256,7 +277,7 @@ SpiBuildDeviceMap( } /* Enumerate buses */ - for (BusNumber = 0; BusNumber < DeviceExtension->PortConfig->NumberOfBuses; BusNumber++) + for (BusNumber = 0; BusNumber < DeviceExtension->NumberOfBuses; BusNumber++) { /* Create 'Scsi Bus X' key */ DPRINT(" Scsi Bus %lu\n", BusNumber); @@ -266,7 +287,7 @@ SpiBuildDeviceMap( RtlInitUnicodeString(&KeyName, NameBuffer); InitializeObjectAttributes(&ObjectAttributes, &KeyName, - 0, + OBJ_KERNEL_HANDLE, ScsiPortKey, NULL); Status = ZwCreateKey(&ScsiBusKey, @@ -275,7 +296,7 @@ SpiBuildDeviceMap( 0, NULL, REG_OPTION_VOLATILE, - &Disposition); + NULL); if (!NT_SUCCESS(Status)) { DPRINT("ZwCreateKey() failed (Status %lx)\n", Status); @@ -291,7 +312,7 @@ SpiBuildDeviceMap( RtlInitUnicodeString(&KeyName, NameBuffer); InitializeObjectAttributes(&ObjectAttributes, &KeyName, - 0, + OBJ_KERNEL_HANDLE, ScsiBusKey, NULL); Status = ZwCreateKey(&ScsiInitiatorKey, @@ -300,7 +321,7 @@ SpiBuildDeviceMap( 0, NULL, REG_OPTION_VOLATILE, - &Disposition); + NULL); if (!NT_SUCCESS(Status)) { DPRINT("ZwCreateKey() failed (Status %lx)\n", Status); @@ -312,202 +333,14 @@ SpiBuildDeviceMap( ZwClose(ScsiInitiatorKey); ScsiInitiatorKey = NULL; - - /* Enumerate targets */ - CurrentTarget = (ULONG)-1; - ScsiTargetKey = NULL; - for (Target = 0; Target < DeviceExtension->PortConfig->MaximumNumberOfTargets; Target++) - { - for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++) - { - LunExtension = SpiGetLunExtension(DeviceExtension, - (UCHAR)BusNumber, - (UCHAR)Target, - (UCHAR)Lun); - if (LunExtension == NULL) - continue; - - if (Target != CurrentTarget) - { - /* Close old target key */ - if (ScsiTargetKey != NULL) - { - ZwClose(ScsiTargetKey); - ScsiTargetKey = NULL; - } - - /* Create 'Target Id X' key */ - DPRINT(" Target Id %lu\n", Target); - swprintf(NameBuffer, - L"Target Id %lu", - Target); - RtlInitUnicodeString(&KeyName, NameBuffer); - InitializeObjectAttributes(&ObjectAttributes, - &KeyName, - 0, - ScsiBusKey, - NULL); - Status = ZwCreateKey(&ScsiTargetKey, - KEY_ALL_ACCESS, - &ObjectAttributes, - 0, - NULL, - REG_OPTION_VOLATILE, - &Disposition); - if (!NT_SUCCESS(Status)) - { - DPRINT("ZwCreateKey() failed (Status %lx)\n", Status); - goto ByeBye; - } - - CurrentTarget = Target; - } - - /* Create 'Logical Unit Id X' key */ - DPRINT(" Logical Unit Id %lu\n", Lun); - swprintf(NameBuffer, - L"Logical Unit Id %lu", - Lun); - RtlInitUnicodeString(&KeyName, NameBuffer); - InitializeObjectAttributes(&ObjectAttributes, - &KeyName, - 0, - ScsiTargetKey, - NULL); - Status = ZwCreateKey(&ScsiLunKey, - KEY_ALL_ACCESS, - &ObjectAttributes, - 0, - NULL, - REG_OPTION_VOLATILE, - &Disposition); - if (!NT_SUCCESS(Status)) - { - DPRINT("ZwCreateKey() failed (Status %lx)\n", Status); - goto ByeBye; - } - - /* Set 'Identifier' (REG_SZ) value */ - swprintf(NameBuffer, - L"%.8S%.16S%.4S", - LunExtension->InquiryData.VendorId, - LunExtension->InquiryData.ProductId, - LunExtension->InquiryData.ProductRevisionLevel); - DPRINT(" Identifier = '%S'\n", NameBuffer); - RtlInitUnicodeString(&ValueName, L"Identifier"); - Status = ZwSetValueKey(ScsiLunKey, - &ValueName, - 0, - REG_SZ, - NameBuffer, - (ULONG)((wcslen(NameBuffer) + 1) * sizeof(WCHAR))); - if (!NT_SUCCESS(Status)) - { - DPRINT("ZwSetValueKey('Identifier') failed (Status %lx)\n", Status); - goto ByeBye; - } - - /* Set 'Type' (REG_SZ) value */ - /* - * See https://docs.microsoft.com/en-us/windows-hardware/drivers/install/identifiers-for-ide-devices - * and https://docs.microsoft.com/en-us/windows-hardware/drivers/install/identifiers-for-scsi-devices - * for a list of types with their human-readable forms. - */ - switch (LunExtension->InquiryData.DeviceType) - { - case 0: - TypeName = L"DiskPeripheral"; - break; - case 1: - TypeName = L"TapePeripheral"; - break; - case 2: - TypeName = L"PrinterPeripheral"; - break; - // case 3: "ProcessorPeripheral", classified as 'other': fall back to default case. - case 4: - TypeName = L"WormPeripheral"; - break; - case 5: - TypeName = L"CdRomPeripheral"; - break; - case 6: - TypeName = L"ScannerPeripheral"; - break; - case 7: - TypeName = L"OpticalDiskPeripheral"; - break; - case 8: - TypeName = L"MediumChangerPeripheral"; - break; - case 9: - TypeName = L"CommunicationsPeripheral"; - break; - - /* New peripheral types (SCSI only) */ - case 10: case 11: - TypeName = L"ASCPrePressGraphicsPeripheral"; - break; - case 12: - TypeName = L"ArrayPeripheral"; - break; - case 13: - TypeName = L"EnclosurePeripheral"; - break; - case 14: - TypeName = L"RBCPeripheral"; - break; - case 15: - TypeName = L"CardReaderPeripheral"; - break; - case 16: - TypeName = L"BridgePeripheral"; - break; - - default: - TypeName = L"OtherPeripheral"; - break; - } - DPRINT(" Type = '%S'\n", TypeName); - RtlInitUnicodeString(&ValueName, L"Type"); - Status = ZwSetValueKey(ScsiLunKey, - &ValueName, - 0, - REG_SZ, - TypeName, - (ULONG)((wcslen(TypeName) + 1) * sizeof(WCHAR))); - if (!NT_SUCCESS(Status)) - { - DPRINT("ZwSetValueKey('Type') failed (Status %lx)\n", Status); - goto ByeBye; - } - - ZwClose(ScsiLunKey); - ScsiLunKey = NULL; - } - - /* Close old target key */ - if (ScsiTargetKey != NULL) - { - ZwClose(ScsiTargetKey); - ScsiTargetKey = NULL; - } - } - - ZwClose(ScsiBusKey); + DeviceExtension->Buses[BusNumber].RegistryMapKey = ScsiBusKey; ScsiBusKey = NULL; } ByeBye: - if (ScsiLunKey != NULL) - ZwClose(ScsiLunKey); - if (ScsiInitiatorKey != NULL) ZwClose(ScsiInitiatorKey); - if (ScsiTargetKey != NULL) - ZwClose(ScsiTargetKey); - if (ScsiBusKey != NULL) ZwClose(ScsiBusKey); @@ -518,3 +351,109 @@ ByeBye: return Status; } + +NTSTATUS +RegistryInitLunKey( + _Inout_ PSCSI_PORT_LUN_EXTENSION LunExtension) +{ + WCHAR nameBuffer[64]; + UNICODE_STRING keyName; + UNICODE_STRING valueName; + OBJECT_ATTRIBUTES objectAttributes; + HANDLE targetKey; + NTSTATUS status; + + // get the LUN's bus key + PSCSI_PORT_DEVICE_EXTENSION portExt = LunExtension->Common.LowerDevice->DeviceExtension; + HANDLE busKey = portExt->Buses[LunExtension->PathId].RegistryMapKey; + + // create/open 'Target Id X' key + swprintf(nameBuffer, L"Target Id %lu", LunExtension->TargetId); + RtlInitUnicodeString(&keyName, nameBuffer); + InitializeObjectAttributes(&objectAttributes, &keyName, OBJ_KERNEL_HANDLE, busKey, NULL); + status = ZwCreateKey(&targetKey, + KEY_ALL_ACCESS, + &objectAttributes, + 0, + NULL, + REG_OPTION_VOLATILE, + NULL); + if (!NT_SUCCESS(status)) + { + DPRINT("ZwCreateKey() failed (Status %lx)\n", status); + return status; + } + + // Create 'Logical Unit Id X' key + swprintf(nameBuffer, L"Logical Unit Id %lu", LunExtension->Lun); + RtlInitUnicodeString(&keyName, nameBuffer); + InitializeObjectAttributes(&objectAttributes, &keyName, OBJ_KERNEL_HANDLE, targetKey, NULL); + status = ZwCreateKey(&LunExtension->RegistryMapKey, + KEY_ALL_ACCESS, + &objectAttributes, + 0, + NULL, + REG_OPTION_VOLATILE, + NULL); + if (!NT_SUCCESS(status)) + { + DPRINT("ZwCreateKey() failed (Status %lx)\n", status); + goto ByeBye; + } + + // Set 'Identifier' (REG_SZ) value + swprintf(nameBuffer, + L"%.8S%.16S%.4S", + LunExtension->InquiryData.VendorId, + LunExtension->InquiryData.ProductId, + LunExtension->InquiryData.ProductRevisionLevel); + RtlInitUnicodeString(&valueName, L"Identifier"); + status = ZwSetValueKey(LunExtension->RegistryMapKey, + &valueName, + 0, + REG_SZ, + nameBuffer, + (wcslen(nameBuffer) + 1) * sizeof(WCHAR)); + if (!NT_SUCCESS(status)) + { + DPRINT("ZwSetValueKey('Identifier') failed (Status %lx)\n", status); + goto ByeBye; + } + + // Set 'Type' (REG_SZ) value + PWCHAR typeName = (PWCHAR)GetPeripheralTypeW(&LunExtension->InquiryData); + DPRINT(" Type = '%S'\n", typeName); + RtlInitUnicodeString(&valueName, L"Type"); + status = ZwSetValueKey(LunExtension->RegistryMapKey, + &valueName, + 0, + REG_SZ, + typeName, + (wcslen(typeName) + 1) * sizeof(WCHAR)); + if (!NT_SUCCESS(status)) + { + DPRINT("ZwSetValueKey('Type') failed (Status %lx)\n", status); + goto ByeBye; + } + + // Set 'InquiryData' (REG_BINARY) value + RtlInitUnicodeString(&valueName, L"InquiryData"); + status = ZwSetValueKey(LunExtension->RegistryMapKey, + &valueName, + 0, + REG_BINARY, + &LunExtension->InquiryData, + INQUIRYDATABUFFERSIZE); + if (!NT_SUCCESS(status)) + { + DPRINT("ZwSetValueKey('InquiryData') failed (Status %lx)\n", status); + goto ByeBye; + } + +ByeBye: + ZwClose(targetKey); + // TODO: maybe we will need it in future + ZwClose(LunExtension->RegistryMapKey); + + return status; +} diff --git a/drivers/storage/port/scsiport/scsi.c b/drivers/storage/port/scsiport/scsi.c index 7feb6da5cdf..29b683d10c0 100644 --- a/drivers/storage/port/scsiport/scsi.c +++ b/drivers/storage/port/scsiport/scsi.c @@ -50,47 +50,17 @@ SpiStatusSrbToNt( static NTSTATUS SpiHandleAttachRelease( - _In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, + _In_ PSCSI_PORT_LUN_EXTENSION LunExtension, _Inout_ PIRP Irp) { - PSCSI_LUN_INFO LunInfo; - PIO_STACK_LOCATION IrpStack; + PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = + LunExtension->Common.LowerDevice->DeviceExtension; PDEVICE_OBJECT DeviceObject; - PSCSI_REQUEST_BLOCK Srb; KIRQL Irql; /* Get pointer to the SRB */ - IrpStack = IoGetCurrentIrpStackLocation(Irp); - Srb = (PSCSI_REQUEST_BLOCK)IrpStack->Parameters.Others.Argument1; - - /* Check if PathId matches number of buses */ - if (DeviceExtension->BusesConfig == NULL || - DeviceExtension->BusesConfig->NumberOfBuses <= Srb->PathId) - { - Srb->SrbStatus = SRB_STATUS_NO_DEVICE; - return STATUS_DEVICE_DOES_NOT_EXIST; - } - - /* Get pointer to LunInfo */ - LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Srb->PathId]->LunInfo; - - /* Find matching LunInfo */ - while (LunInfo) - { - if (LunInfo->PathId == Srb->PathId && - LunInfo->TargetId == Srb->TargetId && - LunInfo->Lun == Srb->Lun) - { - break; - } - - LunInfo = LunInfo->Next; - } - - /* If we couldn't find it - exit */ - if (LunInfo == NULL) - return STATUS_DEVICE_DOES_NOT_EXIST; - + PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp); + PSCSI_REQUEST_BLOCK Srb = IrpStack->Parameters.Scsi.Srb; /* Get spinlock */ KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql); @@ -98,7 +68,7 @@ SpiHandleAttachRelease( /* Release, if asked */ if (Srb->Function == SRB_FUNCTION_RELEASE_DEVICE) { - LunInfo->DeviceClaimed = FALSE; + LunExtension->DeviceClaimed = FALSE; KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql); Srb->SrbStatus = SRB_STATUS_SUCCESS; @@ -106,7 +76,7 @@ SpiHandleAttachRelease( } /* Attach, if not already claimed */ - if (LunInfo->DeviceClaimed) + if (LunExtension->DeviceClaimed) { KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql); Srb->SrbStatus = SRB_STATUS_BUSY; @@ -115,13 +85,13 @@ SpiHandleAttachRelease( } /* Save the device object */ - DeviceObject = LunInfo->DeviceObject; + DeviceObject = LunExtension->Common.DeviceObject; if (Srb->Function == SRB_FUNCTION_CLAIM_DEVICE) - LunInfo->DeviceClaimed = TRUE; + LunExtension->DeviceClaimed = TRUE; if (Srb->Function == SRB_FUNCTION_ATTACH_DEVICE) - LunInfo->DeviceObject = Srb->DataBuffer; + LunExtension->Common.DeviceObject = Srb->DataBuffer; Srb->DataBuffer = DeviceObject; @@ -154,8 +124,8 @@ ScsiPortDispatchScsi( _In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp) { - PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; - PSCSI_PORT_LUN_EXTENSION LunExtension; + PSCSI_PORT_DEVICE_EXTENSION portExt; + PSCSI_PORT_LUN_EXTENSION lunExt; PIO_STACK_LOCATION Stack; PSCSI_REQUEST_BLOCK Srb; KIRQL Irql; @@ -165,10 +135,12 @@ ScsiPortDispatchScsi( DPRINT("ScsiPortDispatchScsi(DeviceObject %p Irp %p)\n", DeviceObject, Irp); - DeviceExtension = DeviceObject->DeviceExtension; Stack = IoGetCurrentIrpStackLocation(Irp); - Srb = Stack->Parameters.Scsi.Srb; + lunExt = DeviceObject->DeviceExtension; + ASSERT(!lunExt->Common.IsFDO); + portExt = lunExt->Common.LowerDevice->DeviceExtension; + if (Srb == NULL) { DPRINT1("ScsiPortDispatchScsi() called with Srb = NULL!\n"); @@ -179,15 +151,16 @@ ScsiPortDispatchScsi( IoCompleteRequest(Irp, IO_NO_INCREMENT); - return (Status); + return Status; } - DPRINT("Srb: %p\n", Srb); - DPRINT("Srb->Function: %lu\n", Srb->Function); - DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb->PathId, Srb->TargetId, Srb->Lun); + DPRINT("Srb: %p, Srb->Function: %lu\n", Srb, Srb->Function); - LunExtension = SpiGetLunExtension(DeviceExtension, Srb->PathId, Srb->TargetId, Srb->Lun); - if (LunExtension == NULL) + Srb->PathId = lunExt->PathId; + Srb->TargetId = lunExt->TargetId; + Srb->Lun = lunExt->Lun; + + if (lunExt == NULL) { DPRINT("ScsiPortDispatchScsi() called with an invalid LUN\n"); Status = STATUS_NO_SUCH_DEVICE; @@ -198,7 +171,7 @@ ScsiPortDispatchScsi( IoCompleteRequest(Irp, IO_NO_INCREMENT); - return (Status); + return Status; } switch (Srb->Function) @@ -206,7 +179,7 @@ ScsiPortDispatchScsi( case SRB_FUNCTION_SHUTDOWN: case SRB_FUNCTION_FLUSH: DPRINT(" SRB_FUNCTION_SHUTDOWN or FLUSH\n"); - if (DeviceExtension->CachesData == FALSE) + if (portExt->CachesData == FALSE) { /* All success here */ Srb->SrbStatus = SRB_STATUS_SUCCESS; @@ -225,7 +198,7 @@ ScsiPortDispatchScsi( if (Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE) { /* Start IO directly */ - IoStartPacket(DeviceObject, Irp, NULL, NULL); + IoStartPacket(portExt->Common.DeviceObject, Irp, NULL, NULL); } else { @@ -235,13 +208,12 @@ ScsiPortDispatchScsi( KeRaiseIrql(DISPATCH_LEVEL, &oldIrql); /* Insert IRP into the queue */ - if (!KeInsertByKeyDeviceQueue( - &LunExtension->DeviceQueue, - &Irp->Tail.Overlay.DeviceQueueEntry, - Srb->QueueSortKey)) + if (!KeInsertByKeyDeviceQueue(&lunExt->DeviceQueue, + &Irp->Tail.Overlay.DeviceQueueEntry, + Srb->QueueSortKey)) { /* It means the queue is empty, and we just start this request */ - IoStartPacket(DeviceObject, Irp, NULL, NULL); + IoStartPacket(portExt->Common.DeviceObject, Irp, NULL, NULL); } /* Back to the old IRQL */ @@ -254,39 +226,40 @@ ScsiPortDispatchScsi( DPRINT(" SRB_FUNCTION_CLAIM_DEVICE or ATTACH\n"); /* Reference device object and keep the device object */ - Status = SpiHandleAttachRelease(DeviceExtension, Irp); + Status = SpiHandleAttachRelease(lunExt, Irp); break; case SRB_FUNCTION_RELEASE_DEVICE: DPRINT(" SRB_FUNCTION_RELEASE_DEVICE\n"); /* Dereference device object and clear the device object */ - Status = SpiHandleAttachRelease(DeviceExtension, Irp); + Status = SpiHandleAttachRelease(lunExt, Irp); break; case SRB_FUNCTION_RELEASE_QUEUE: DPRINT(" SRB_FUNCTION_RELEASE_QUEUE\n"); /* Guard with the spinlock */ - KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql); + KeAcquireSpinLock(&portExt->SpinLock, &Irql); - if (!(LunExtension->Flags & LUNEX_FROZEN_QUEUE)) + if (!(lunExt->Flags & LUNEX_FROZEN_QUEUE)) { DPRINT("Queue is not frozen really\n"); - KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql); + KeReleaseSpinLock(&portExt->SpinLock, Irql); Srb->SrbStatus = SRB_STATUS_SUCCESS; Status = STATUS_SUCCESS; break; + } /* Unfreeze the queue */ - LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE; + lunExt->Flags &= ~LUNEX_FROZEN_QUEUE; - if (LunExtension->SrbInfo.Srb == NULL) + if (lunExt->SrbInfo.Srb == NULL) { /* Get next logical unit request */ - SpiGetNextRequestFromLun(DeviceExtension, LunExtension); + SpiGetNextRequestFromLun(portExt, lunExt); /* SpiGetNextRequestFromLun() releases the spinlock */ KeLowerIrql(Irql); @@ -294,7 +267,7 @@ ScsiPortDispatchScsi( else { DPRINT("The queue has active request\n"); - KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql); + KeReleaseSpinLock(&portExt->SpinLock, Irql); } Srb->SrbStatus = SRB_STATUS_SUCCESS; @@ -305,23 +278,23 @@ ScsiPortDispatchScsi( DPRINT(" SRB_FUNCTION_FLUSH_QUEUE\n"); /* Guard with the spinlock */ - KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql); + KeAcquireSpinLock(&portExt->SpinLock, &Irql); - if (!(LunExtension->Flags & LUNEX_FROZEN_QUEUE)) + if (!(lunExt->Flags & LUNEX_FROZEN_QUEUE)) { DPRINT("Queue is not frozen really\n"); - KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql); + KeReleaseSpinLock(&portExt->SpinLock, Irql); Status = STATUS_INVALID_DEVICE_REQUEST; break; } /* Make sure there is no active request */ - ASSERT(LunExtension->SrbInfo.Srb == NULL); + ASSERT(lunExt->SrbInfo.Srb == NULL); /* Compile a list from the device queue */ IrpList = NULL; - while ((Entry = KeRemoveDeviceQueue(&LunExtension->DeviceQueue)) != NULL) + while ((Entry = KeRemoveDeviceQueue(&lunExt->DeviceQueue)) != NULL) { NextIrp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DeviceQueueEntry); @@ -339,10 +312,10 @@ ScsiPortDispatchScsi( } /* Unfreeze the queue */ - LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE; + lunExt->Flags &= ~LUNEX_FROZEN_QUEUE; /* Release the spinlock */ - KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql); + KeReleaseSpinLock(&portExt->SpinLock, Irql); /* Complete those requests */ while (IrpList) @@ -415,7 +388,7 @@ SpiGetNextRequestFromLun( KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); /* Start the next pending request */ - IoStartPacket(DeviceExtension->DeviceObject, NextIrp, (PULONG)NULL, NULL); + IoStartPacket(DeviceExtension->Common.DeviceObject, NextIrp, (PULONG)NULL, NULL); return; } @@ -454,7 +427,7 @@ SpiGetNextRequestFromLun( KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); /* Start the next pending request */ - IoStartPacket(DeviceExtension->DeviceObject, NextIrp, (PULONG)NULL, NULL); + IoStartPacket(DeviceExtension->Common.DeviceObject, NextIrp, (PULONG)NULL, NULL); } else { @@ -525,7 +498,7 @@ SpiSenseCompletionRoutine( static VOID SpiSendRequestSense( - _In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, + _In_ PSCSI_PORT_LUN_EXTENSION LunExtension, _In_ PSCSI_REQUEST_BLOCK InitialSrb) { PSCSI_REQUEST_BLOCK Srb; @@ -544,7 +517,7 @@ SpiSendRequestSense( /* Allocate IRP */ LargeInt.QuadPart = (LONGLONG) 1; Irp = IoBuildAsynchronousFsdRequest(IRP_MJ_READ, - DeviceExtension->DeviceObject, + LunExtension->Common.DeviceObject, InitialSrb->SenseInfoBuffer, InitialSrb->SenseInfoBufferLength, &LargeInt, @@ -621,7 +594,7 @@ SpiSendRequestSense( Srb->NextSrb = 0; /* Call the driver */ - (VOID)IoCallDriver(DeviceExtension->DeviceObject, Irp); + (VOID)IoCallDriver(LunExtension->Common.DeviceObject, Irp); DPRINT("SpiSendRequestSense() done\n"); } @@ -642,12 +615,11 @@ SpiProcessCompletedRequest( Srb = SrbInfo->Srb; Irp = Srb->OriginalRequest; + PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Irp); /* Get Lun extension */ - LunExtension = SpiGetLunExtension(DeviceExtension, - Srb->PathId, - Srb->TargetId, - Srb->Lun); + LunExtension = IoStack->DeviceObject->DeviceExtension; + ASSERT(LunExtension && !LunExtension->Common.IsFDO); if (Srb->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION && DeviceExtension->MapBuffers && @@ -697,7 +669,7 @@ SpiProcessCompletedRequest( !(*NeedToCallStartIo)) { /* We're not busy, but we have a request pending */ - IoStartNextPacket(DeviceExtension->DeviceObject, FALSE); + IoStartNextPacket(DeviceExtension->Common.DeviceObject, FALSE); } } @@ -931,7 +903,7 @@ Error: KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); /* Send RequestSense */ - SpiSendRequestSense(DeviceExtension, Srb); + SpiSendRequestSense(LunExtension, Srb); /* Exit */ return; @@ -950,10 +922,11 @@ NTAPI ScsiPortStartPacket( _In_ PVOID Context) { - PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; PIO_STACK_LOCATION IrpStack; PSCSI_REQUEST_BLOCK Srb; PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)Context; + PSCSI_PORT_COMMON_EXTENSION CommonExtension = DeviceObject->DeviceExtension; + PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; PSCSI_PORT_LUN_EXTENSION LunExtension; PSCSI_REQUEST_BLOCK_INFO SrbInfo; BOOLEAN Result; @@ -961,16 +934,20 @@ ScsiPortStartPacket( DPRINT("ScsiPortStartPacket() called\n"); - DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension; - IrpStack = IoGetCurrentIrpStackLocation(DeviceObject->CurrentIrp); Srb = IrpStack->Parameters.Scsi.Srb; - /* Get LUN extension */ - LunExtension = SpiGetLunExtension(DeviceExtension, - Srb->PathId, - Srb->TargetId, - Srb->Lun); + if (CommonExtension->IsFDO) // IsFDO + { + DeviceExtension = DeviceObject->DeviceExtension; + LunExtension = IrpStack->DeviceObject->DeviceExtension; + ASSERT(LunExtension && !LunExtension->Common.IsFDO); + } + else + { + LunExtension = DeviceObject->DeviceExtension; + DeviceExtension = LunExtension->Common.LowerDevice->DeviceExtension; + } /* Check if we are in a reset state */ if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET) @@ -1006,11 +983,7 @@ ScsiPortStartPacket( if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND) { /* Get pointer to SRB info structure */ - SrbInfo = SpiGetSrbData(DeviceExtension, - Srb->PathId, - Srb->TargetId, - Srb->Lun, - Srb->QueueTag); + SrbInfo = SpiGetSrbData(DeviceExtension, LunExtension, Srb->QueueTag); /* Check if the request is still "active" */ if (SrbInfo == NULL || @@ -1036,7 +1009,7 @@ ScsiPortStartPacket( DeviceExtension->MiniPortDeviceExtension); /* They might ask for some work, so queue the DPC for them */ - IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL); + IoRequestDpc(DeviceExtension->Common.DeviceObject, NULL, NULL); /* We're done in this branch */ return TRUE; @@ -1096,7 +1069,7 @@ ScsiPortStartPacket( /* If notification is needed, then request a DPC */ if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED) - IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL); + IoRequestDpc(DeviceExtension->Common.DeviceObject, NULL, NULL); return Result; } @@ -1140,10 +1113,9 @@ SpiSaveInterruptData(IN PVOID Context) /* Get SRB and LunExtension */ Srb = SrbInfo->Srb; - LunExtension = SpiGetLunExtension(DeviceExtension, - Srb->PathId, - Srb->TargetId, - Srb->Lun); + PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Srb->OriginalRequest); + LunExtension = IoStack->DeviceObject->DeviceExtension; + ASSERT(LunExtension && !LunExtension->Common.IsFDO); /* We have to check special cases if request is unsuccessful*/ if (Srb->SrbStatus != SRB_STATUS_SUCCESS) @@ -1359,7 +1331,7 @@ TryAgain: /* If we ready for next packet, start it */ if (InterruptData.Flags & SCSI_PORT_NEXT_REQUEST_READY) - IoStartNextPacket(DeviceExtension->DeviceObject, FALSE); + IoStartNextPacket(DeviceExtension->Common.DeviceObject, FALSE); NeedToStartIo = FALSE; @@ -1456,11 +1428,7 @@ SpiAllocateSrbStructures( /* Treat the abort request in a special way */ if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND) { - SrbInfo = SpiGetSrbData(DeviceExtension, - Srb->PathId, - Srb->TargetId, - Srb->Lun, - Srb->QueueTag); + SrbInfo = SpiGetSrbData(DeviceExtension, LunExtension, Srb->QueueTag); } else if (Srb->SrbFlags & (SRB_FLAGS_QUEUE_ACTION_ENABLE | SRB_FLAGS_NO_QUEUE_FREEZE) && @@ -1606,20 +1574,18 @@ ScsiPortStartIo( DeviceExtension = DeviceObject->DeviceExtension; IrpStack = IoGetCurrentIrpStackLocation(Irp); + LunExtension = IrpStack->DeviceObject->DeviceExtension; - DPRINT("DeviceExtension %p\n", DeviceExtension); + ASSERT(DeviceExtension->Common.IsFDO); + ASSERT(!LunExtension->Common.IsFDO); + + DPRINT("LunExtension %p DeviceExtension %p\n", LunExtension, DeviceExtension); Srb = IrpStack->Parameters.Scsi.Srb; /* Apply "default" flags */ Srb->SrbFlags |= DeviceExtension->SrbFlags; - /* Get LUN extension */ - LunExtension = SpiGetLunExtension(DeviceExtension, - Srb->PathId, - Srb->TargetId, - Srb->Lun); - if (DeviceExtension->NeedSrbDataAlloc || DeviceExtension->NeedSrbExtensionAlloc) { @@ -1699,7 +1665,7 @@ ScsiPortStartIo( /* Allocate adapter channel */ Status = IoAllocateAdapterChannel(DeviceExtension->AdapterObject, - DeviceExtension->DeviceObject, + DeviceExtension->Common.DeviceObject, SrbInfo->NumberOfMapRegisters, SpiAdapterControl, SrbInfo); @@ -1717,7 +1683,7 @@ ScsiPortStartIo( DeviceExtension + 1); /* Request DPC for that work */ - IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL); + IoRequestDpc(DeviceExtension->Common.DeviceObject, NULL, NULL); } /* Control goes to SpiAdapterControl */ diff --git a/drivers/storage/port/scsiport/scsiport.c b/drivers/storage/port/scsiport/scsiport.c index 1f527947d25..8e6e3e3c198 100644 --- a/drivers/storage/port/scsiport/scsiport.c +++ b/drivers/storage/port/scsiport/scsiport.c @@ -4,6 +4,7 @@ * 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 *****************************************************************/ @@ -112,8 +113,43 @@ NTSTATUS NTAPI DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) { - DPRINT("ScsiPort Driver %s\n", VERSION); - return(STATUS_SUCCESS); + 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; } @@ -202,8 +238,6 @@ ScsiPortCompleteRequest(IN PVOID HwDeviceExtension, PSCSI_PORT_LUN_EXTENSION LunExtension; PSCSI_REQUEST_BLOCK_INFO SrbInfo; PLIST_ENTRY ListEntry; - ULONG BusNumber; - ULONG Target; DPRINT("ScsiPortCompleteRequest() called\n"); @@ -212,60 +246,56 @@ ScsiPortCompleteRequest(IN PVOID HwDeviceExtension, MiniPortDeviceExtension); /* Go through all buses */ - for (BusNumber = 0; BusNumber < 8; BusNumber++) + for (UINT8 pathId = 0; pathId < DeviceExtension->NumberOfBuses; pathId++) { - /* Go through all targets */ - for (Target = 0; Target < DeviceExtension->MaxTargedIds; Target++) + 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) { - /* Get logical unit list head */ - LunExtension = DeviceExtension->LunExtensionList[Target % 8]; + LunExtension = CONTAINING_RECORD(lunEntry, SCSI_PORT_LUN_EXTENSION, LunEntry); - /* Go through all logical units */ - while (LunExtension) + /* 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)) { - /* 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) { - /* 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"); + /* 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; - } + /* Issue a notification request */ + ScsiPortNotification(RequestComplete, + HwDeviceExtension, + LunExtension->CompletedAbortRequests); } - /* Advance to the next one */ - LunExtension = LunExtension->Next; + /* 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; + } } } } @@ -468,10 +498,8 @@ ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension, return NULL; } - LunExtension = SpiGetLunExtension(DeviceExtension, - PathId, - TargetId, - Lun); + LunExtension = GetLunByPath(DeviceExtension, PathId, TargetId, Lun); + /* Check that the logical unit exists */ if (!LunExtension) { @@ -517,12 +545,12 @@ ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension, } 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, - Srb->PathId, - Srb->TargetId, - Srb->Lun, - Srb->QueueTag); + SrbInfo = SpiGetSrbData(DeviceExtension, LunExtension, Srb->QueueTag); SGList = SrbInfo->ScatterGather; @@ -816,7 +844,6 @@ ScsiPortInitialize( PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = NULL; PCONFIGURATION_INFORMATION SystemConfig; PPORT_CONFIGURATION_INFORMATION PortConfig; - PORT_CONFIGURATION_INFORMATION InitialPortConfig; CONFIGURATION_INFO ConfigInfo; ULONG DeviceExtensionSize; ULONG PortConfigSize; @@ -829,16 +856,10 @@ ScsiPortInitialize( PCI_SLOT_NUMBER SlotNumber; PDEVICE_OBJECT PortDeviceObject; - WCHAR NameBuffer[80]; UNICODE_STRING DeviceName; - WCHAR DosNameBuffer[80]; - UNICODE_STRING DosDeviceName; PIO_SCSI_CAPABILITIES PortCapabilities; PCM_RESOURCE_LIST ResourceList; - BOOLEAN Conflict; - SIZE_T BusConfigSize; - DPRINT ("ScsiPortInitialize() called!\n"); @@ -849,15 +870,46 @@ ScsiPortInitialize( (HwInitializationData->HwFindAdapter == NULL) || (HwInitializationData->HwResetBus == NULL)) { - return STATUS_INVALID_PARAMETER; + 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(); @@ -880,8 +932,11 @@ ScsiPortInitialize( return STATUS_INSUFFICIENT_RESOURCES; } - /* Open registry keys */ - SpiInitOpenKeys(&ConfigInfo, (PUNICODE_STRING)Argument2); + /* 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; @@ -895,11 +950,18 @@ ScsiPortInitialize( while (TRUE) { + WCHAR NameBuffer[27]; /* Create a unicode device name */ swprintf(NameBuffer, L"\\Device\\ScsiPort%lu", SystemConfig->ScsiPortCount); - RtlInitUnicodeString(&DeviceName, NameBuffer); + 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); @@ -908,7 +970,7 @@ ScsiPortInitialize( DeviceExtensionSize, &DeviceName, FILE_DEVICE_CONTROLLER, - 0, + FILE_DEVICE_SECURE_OPEN, FALSE, &PortDeviceObject); @@ -919,7 +981,7 @@ ScsiPortInitialize( break; } - DPRINT ("Created device: %wZ (%p)\n", &DeviceName, PortDeviceObject); + DPRINT1("Created device: %wZ (%p)\n", &DeviceName, PortDeviceObject); /* Set the buffering strategy here... */ PortDeviceObject->Flags |= DO_DIRECT_IO; @@ -928,9 +990,11 @@ ScsiPortInitialize( /* Fill Device Extension */ DeviceExtension = PortDeviceObject->DeviceExtension; RtlZeroMemory(DeviceExtension, DeviceExtensionSize); + DeviceExtension->Common.DeviceObject = PortDeviceObject; + DeviceExtension->Common.IsFDO = TRUE; DeviceExtension->Length = DeviceExtensionSize; - DeviceExtension->DeviceObject = PortDeviceObject; DeviceExtension->PortNumber = SystemConfig->ScsiPortCount; + DeviceExtension->DeviceName = DeviceName; /* Driver's routines... */ DeviceExtension->HwInitialize = HwInitializationData->HwInitialize; @@ -941,13 +1005,10 @@ ScsiPortInitialize( /* Extensions sizes */ DeviceExtension->MiniPortExtensionSize = HwInitializationData->DeviceExtensionSize; - DeviceExtension->LunExtensionSize = HwInitializationData->SpecificLuExtensionSize; - DeviceExtension->SrbExtensionSize = HwInitializationData->SrbExtensionSize; - - /* Round Srb extension size to the quadword */ + DeviceExtension->LunExtensionSize = + ALIGN_UP(HwInitializationData->SpecificLuExtensionSize, INT64); DeviceExtension->SrbExtensionSize = - ~(sizeof(LONGLONG) - 1) & (DeviceExtension->SrbExtensionSize + - sizeof(LONGLONG) - 1); + ALIGN_UP(HwInitializationData->SrbExtensionSize, INT64); /* Fill some numbers (bus count, lun count, etc) */ DeviceExtension->MaxLunCount = SCSI_MAXIMUM_LOGICAL_UNITS; @@ -975,22 +1036,10 @@ ScsiPortInitialize( CreatePortConfig: - Status = SpiCreatePortConfig(DeviceExtension, - HwInitializationData, - &ConfigInfo, - &InitialPortConfig, - FirstConfigCall); - - if (!NT_SUCCESS(Status)) - { - DPRINT("SpiCreatePortConfig() failed with Status 0x%08X\n", Status); - break; - } - /* Allocate and initialize port configuration info */ - PortConfigSize = (sizeof(PORT_CONFIGURATION_INFORMATION) + - HwInitializationData->NumberOfAccessRanges * - sizeof(ACCESS_RANGE) + 7) & ~7; + 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 */ @@ -1000,14 +1049,20 @@ CreatePortConfig: 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 information here */ - RtlCopyMemory(PortConfig, - &InitialPortConfig, - sizeof(PORT_CONFIGURATION_INFORMATION)); - - /* Copy extension sizes into the PortConfig */ PortConfig->SpecificLuExtensionSize = DeviceExtension->LunExtensionSize; PortConfig->SrbExtensionSize = DeviceExtension->SrbExtensionSize; @@ -1015,11 +1070,7 @@ CreatePortConfig: /* Initialize Access ranges */ if (HwInitializationData->NumberOfAccessRanges != 0) { - PortConfig->AccessRanges = (PVOID)(PortConfig+1); - - /* Align to LONGLONG */ - PortConfig->AccessRanges = (PVOID)((ULONG_PTR)(PortConfig->AccessRanges) + 7); - PortConfig->AccessRanges = (PVOID)((ULONG_PTR)(PortConfig->AccessRanges) & ~7); + PortConfig->AccessRanges = ALIGN_UP_POINTER(PortConfig + 1, INT64); /* Copy the data */ RtlCopyMemory(PortConfig->AccessRanges, @@ -1113,54 +1164,44 @@ CreatePortConfig: (PortConfig->SrbExtensionSize != DeviceExtension->SrbExtensionSize)) { /* Set it (rounding to LONGLONG again) */ - DeviceExtension->SrbExtensionSize = - (PortConfig->SrbExtensionSize + sizeof(LONGLONG)) & ~(sizeof(LONGLONG) - 1); + DeviceExtension->SrbExtensionSize = ALIGN_UP(PortConfig->SrbExtensionSize, INT64); } /* The same with LUN extension size */ if (PortConfig->SpecificLuExtensionSize != DeviceExtension->LunExtensionSize) DeviceExtension->LunExtensionSize = PortConfig->SpecificLuExtensionSize; - if (!((HwInitializationData->AdapterInterfaceType == PCIBus) && - (HwInitializationData->VendorIdLength > 0) && - (HwInitializationData->VendorId != NULL) && - (HwInitializationData->DeviceIdLength > 0) && - (HwInitializationData->DeviceId != NULL))) + /* 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)) { - /* Construct a resource list */ - ResourceList = SpiConfigToResource(DeviceExtension, PortConfig); - - if (ResourceList) - { - UNICODE_STRING UnicodeString; - RtlInitUnicodeString(&UnicodeString, L"ScsiAdapter"); - DPRINT("Reporting resources\n"); - Status = IoReportResourceUsage(&UnicodeString, - DriverObject, - NULL, - 0, - PortDeviceObject, - ResourceList, - FIELD_OFFSET(CM_RESOURCE_LIST, - List[0].PartialResourceList.PartialDescriptors) + - ResourceList->List[0].PartialResourceList.Count * - sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR), - FALSE, - &Conflict); - ExFreePool(ResourceList); - - /* In case of a failure or a conflict, break */ - if (Conflict || (!NT_SUCCESS(Status))) - { - if (Conflict) - Status = STATUS_CONFLICTING_ADDRESSES; - break; - } - } + DPRINT1("IoReportDetectedDevice failed. Status: 0x%x\n", Status); + __debugbreak(); + break; } - /* Reset the Conflict var */ - Conflict = FALSE; + 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) @@ -1168,12 +1209,30 @@ CreatePortConfig: else DeviceExtension->MaxTargedIds = PortConfig->MaximumNumberOfTargets; - DeviceExtension->BusNum = PortConfig->NumberOfBuses; + 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; @@ -1283,43 +1342,18 @@ CreatePortConfig: } } - CallHWInitialize(DeviceExtension); + FdoCallHWInitialize(DeviceExtension); - /* Start our timer */ - IoStartTimer(PortDeviceObject); + Status = FdoStartAdapter(DeviceExtension); - /* Initialize bus scanning information */ - BusConfigSize = FIELD_OFFSET( - BUSES_CONFIGURATION_INFORMATION, - BusScanInfo[DeviceExtension->PortConfig->NumberOfBuses]); - DeviceExtension->BusesConfig = - ExAllocatePoolWithTag(PagedPool, BusConfigSize, TAG_SCSIPORT); - if (!DeviceExtension->BusesConfig) + if (!NT_SUCCESS(Status)) { - DPRINT1("Out of resources!\n"); - Status = STATUS_INSUFFICIENT_RESOURCES; + DPRINT1("Failed to start the legacy adapter. Status 0x%x\n", Status); break; } - /* Zero it */ - RtlZeroMemory(DeviceExtension->BusesConfig, BusConfigSize); + FdoScanAdapter(DeviceExtension); - /* Store number of buses there */ - DeviceExtension->BusesConfig->NumberOfBuses = (UCHAR)DeviceExtension->BusNum; - - /* Scan the adapter for devices */ - SpiScanAdapter(DeviceExtension); - - /* Build the registry device map */ - SpiBuildDeviceMap(DeviceExtension, (PUNICODE_STRING)Argument2); - - /* Create the dos device link */ - swprintf(DosNameBuffer, L"\\??\\Scsi%lu:", SystemConfig->ScsiPortCount); - RtlInitUnicodeString(&DosDeviceName, DosNameBuffer); - IoCreateSymbolicLink(&DosDeviceName, &DeviceName); - - /* Increase the port count */ - SystemConfig->ScsiPortCount++; FirstConfigCall = FALSE; /* Increase adapter number and bus number respectively */ @@ -1334,7 +1368,10 @@ CreatePortConfig: } /* Clean up the mess */ - SpiCleanupAfterInit(DeviceExtension); + if (!NT_SUCCESS(Status) && PortDeviceObject) + { + FdoRemoveAdapter(DeviceExtension); + } /* Close registry keys */ if (ConfigInfo.ServiceKey != NULL) @@ -1461,9 +1498,12 @@ ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType, IN PVOID HwDevi } 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, Srb->PathId, Srb->TargetId, Srb->Lun, Srb->QueueTag); + SrbData = SpiGetSrbData(DeviceExtension, LunExtension, Srb->QueueTag); /* Make sure there are no CompletedRequests and there is a Srb */ ASSERT(SrbData->CompletedRequests == NULL && SrbData->Srb != NULL); @@ -1504,7 +1544,7 @@ ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType, IN PVOID HwDevi DeviceExtension->InterruptData.Flags |= SCSI_PORT_NEXT_REQUEST_READY; /* Get the LUN extension */ - LunExtension = SpiGetLunExtension(DeviceExtension, PathId, TargetId, Lun); + LunExtension = GetLunByPath(DeviceExtension, PathId, TargetId, Lun); /* If returned LunExtension is NULL, break out */ if (!LunExtension) @@ -2104,7 +2144,7 @@ ScsiPortIsr( /* If flag of notification is set - queue a DPC */ if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED) { - IoRequestDpc(DeviceExtension->DeviceObject, + IoRequestDpc(DeviceExtension->Common.DeviceObject, DeviceExtension->CurrentIrp, DeviceExtension); } @@ -2140,7 +2180,7 @@ SpiProcessTimeout(PVOID ServiceContext) { DPRINT("Resetting the bus\n"); - for (Bus = 0; Bus < DeviceExtension->BusNum; Bus++) + for (Bus = 0; Bus < DeviceExtension->NumberOfBuses; Bus++) { DeviceExtension->HwResetBus(DeviceExtension->MiniPortDeviceExtension, Bus); @@ -2151,7 +2191,7 @@ SpiProcessTimeout(PVOID ServiceContext) /* If miniport requested - request a dpc for it */ if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED) - IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL); + IoRequestDpc(DeviceExtension->Common.DeviceObject, NULL, NULL); } return TRUE; @@ -2176,7 +2216,7 @@ SpiResetBus(PVOID ServiceContext) /* If miniport requested - give him a DPC */ if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED) - IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL); + IoRequestDpc(DeviceExtension->Common.DeviceObject, NULL, NULL); return TRUE; } @@ -2198,7 +2238,6 @@ ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject, { PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; PSCSI_PORT_LUN_EXTENSION LunExtension; - ULONG Lun; PIRP Irp; DPRINT("ScsiPortIoTimer()\n"); @@ -2219,7 +2258,7 @@ ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject, /* Timeout, process it */ if (KeSynchronizeExecution(DeviceExtension->Interrupt[0], SpiProcessTimeout, - DeviceExtension->DeviceObject)) + DeviceExtension->Common.DeviceObject)) { DPRINT("Error happened during processing timeout, but nothing critical\n"); } @@ -2232,12 +2271,16 @@ ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject, } /* Per-Lun scanning of timeouts is needed... */ - for (Lun = 0; Lun < LUS_NUMBER; Lun++) + for (UINT8 pathId = 0; pathId < DeviceExtension->NumberOfBuses; pathId++) { - LunExtension = DeviceExtension->LunExtensionList[Lun]; + PSCSI_BUS_INFO bus = &DeviceExtension->Buses[pathId]; - while (LunExtension) + 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 & @@ -2283,8 +2326,6 @@ ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject, /* Decrement the timeout counter */ LunExtension->RequestTimeout--; } - - LunExtension = LunExtension->Next; } } @@ -2320,7 +2361,7 @@ SpiMiniportTimerDpc(IN struct _KDPC *Dpc, if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED) { ScsiPortDpcForIsr(NULL, - DeviceExtension->DeviceObject, + DeviceExtension->Common.DeviceObject, NULL, NULL); } @@ -2398,8 +2439,8 @@ TryNextAd: { /* Open registry key for HW database */ InitializeObjectAttributes(&ObjectAttributes, - DeviceExtension->DeviceObject->DriverObject->HardwareDatabase, - OBJ_CASE_INSENSITIVE, + DeviceExtension->Common.DeviceObject->DriverObject->HardwareDatabase, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); @@ -2418,7 +2459,7 @@ TryNextAd: /* Open device key */ InitializeObjectAttributes(&ObjectAttributes, &UnicodeString, - OBJ_CASE_INSENSITIVE, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, RootKey, NULL); @@ -2479,7 +2520,7 @@ TryNextAd: /* Open the service key */ InitializeObjectAttributes(&ObjectAttributes, &UnicodeString, - OBJ_CASE_INSENSITIVE, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, InternalConfigInfo->ServiceKey, NULL); @@ -3012,5 +3053,3 @@ ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address) DPRINT("ScsiPortConvertPhysicalAddressToUlong()\n"); return(Address.u.LowPart); } - -/* EOF */ diff --git a/drivers/storage/port/scsiport/scsiport.h b/drivers/storage/port/scsiport/scsiport.h index 73c9a91599b..b2db80654f0 100644 --- a/drivers/storage/port/scsiport/scsiport.h +++ b/drivers/storage/port/scsiport/scsiport.h @@ -7,15 +7,16 @@ #pragma once -#include -#include +#include #include #include #include #include #include -#define VERSION "0.0.3" +#ifdef DBG +#include +#endif #define TAG_SCSIPORT 'ISCS' @@ -25,29 +26,29 @@ #define MAX_SG_LIST 17 /* Flags */ -#define SCSI_PORT_DEVICE_BUSY 0x0001 -#define SCSI_PORT_LU_ACTIVE 0x0002 -#define SCSI_PORT_NOTIFICATION_NEEDED 0x0004 -#define SCSI_PORT_NEXT_REQUEST_READY 0x0008 -#define SCSI_PORT_FLUSH_ADAPTERS 0x0010 -#define SCSI_PORT_MAP_TRANSFER 0x0020 -#define SCSI_PORT_RESET 0x0080 -#define SCSI_PORT_RESET_REQUEST 0x0100 -#define SCSI_PORT_RESET_REPORTED 0x0200 -#define SCSI_PORT_REQUEST_PENDING 0x0800 -#define SCSI_PORT_DISCONNECT_ALLOWED 0x1000 -#define SCSI_PORT_DISABLE_INT_REQUESET 0x2000 -#define SCSI_PORT_DISABLE_INTERRUPTS 0x4000 -#define SCSI_PORT_ENABLE_INT_REQUEST 0x8000 -#define SCSI_PORT_TIMER_NEEDED 0x10000 +#define SCSI_PORT_DEVICE_BUSY 0x00001 +#define SCSI_PORT_LU_ACTIVE 0x00002 +#define SCSI_PORT_NOTIFICATION_NEEDED 0x00004 +#define SCSI_PORT_NEXT_REQUEST_READY 0x00008 +#define SCSI_PORT_FLUSH_ADAPTERS 0x00010 +#define SCSI_PORT_MAP_TRANSFER 0x00020 +#define SCSI_PORT_RESET 0x00080 +#define SCSI_PORT_RESET_REQUEST 0x00100 +#define SCSI_PORT_RESET_REPORTED 0x00200 +#define SCSI_PORT_REQUEST_PENDING 0x00800 +#define SCSI_PORT_DISCONNECT_ALLOWED 0x01000 +#define SCSI_PORT_DISABLE_INT_REQUESET 0x02000 +#define SCSI_PORT_DISABLE_INTERRUPTS 0x04000 +#define SCSI_PORT_ENABLE_INT_REQUEST 0x08000 +#define SCSI_PORT_TIMER_NEEDED 0x10000 /* LUN Extension flags*/ -#define LUNEX_FROZEN_QUEUE 0x0001 -#define LUNEX_NEED_REQUEST_SENSE 0x0004 -#define LUNEX_BUSY 0x0008 -#define LUNEX_FULL_QUEUE 0x0010 -#define LUNEX_REQUEST_PENDING 0x0020 -#define SCSI_PORT_SCAN_IN_PROGRESS 0x8000 +#define LUNEX_FROZEN_QUEUE 0x0001 +#define LUNEX_NEED_REQUEST_SENSE 0x0004 +#define LUNEX_BUSY 0x0008 +#define LUNEX_FULL_QUEUE 0x0010 +#define LUNEX_REQUEST_PENDING 0x0020 +#define SCSI_PORT_SCAN_IN_PROGRESS 0x8000 typedef enum _SCSI_PORT_TIMER_STATES @@ -115,18 +116,27 @@ typedef struct _SCSI_REQUEST_BLOCK_INFO SCSI_SG_ADDRESS ScatterGatherList[MAX_SG_LIST]; } SCSI_REQUEST_BLOCK_INFO, *PSCSI_REQUEST_BLOCK_INFO; +typedef struct _SCSI_PORT_COMMON_EXTENSION +{ + PDEVICE_OBJECT DeviceObject; + PDEVICE_OBJECT LowerDevice; + BOOLEAN IsFDO; +} SCSI_PORT_COMMON_EXTENSION, *PSCSI_PORT_COMMON_EXTENSION; + +// PDO device typedef struct _SCSI_PORT_LUN_EXTENSION { + SCSI_PORT_COMMON_EXTENSION Common; + UCHAR PathId; UCHAR TargetId; UCHAR Lun; ULONG Flags; - struct _SCSI_PORT_LUN_EXTENSION *Next; + LIST_ENTRY LunEntry; BOOLEAN DeviceClaimed; - PDEVICE_OBJECT DeviceObject; INQUIRYDATA InquiryData; @@ -146,6 +156,8 @@ typedef struct _SCSI_PORT_LUN_EXTENSION SCSI_REQUEST_BLOCK_INFO SrbInfo; + HANDLE RegistryMapKey; + /* More data? */ UCHAR MiniportLunExtension[1]; /* must be the last entry */ @@ -153,31 +165,14 @@ typedef struct _SCSI_PORT_LUN_EXTENSION /* Structures for inquiries support */ -typedef struct _SCSI_LUN_INFO +typedef struct _SCSI_BUS_INFO { - UCHAR PathId; - UCHAR TargetId; - UCHAR Lun; - BOOLEAN DeviceClaimed; - PVOID DeviceObject; - struct _SCSI_LUN_INFO *Next; - UCHAR InquiryData[INQUIRYDATABUFFERSIZE]; -} SCSI_LUN_INFO, *PSCSI_LUN_INFO; - -typedef struct _SCSI_BUS_SCAN_INFO -{ - USHORT Length; + LIST_ENTRY LunsListHead; UCHAR LogicalUnitsCount; + UCHAR TargetsCount; UCHAR BusIdentifier; - PSCSI_LUN_INFO LunInfo; -} SCSI_BUS_SCAN_INFO, *PSCSI_BUS_SCAN_INFO; - -typedef struct _BUSES_CONFIGURATION_INFORMATION -{ - UCHAR NumberOfBuses; - PSCSI_BUS_SCAN_INFO BusScanInfo[1]; -} BUSES_CONFIGURATION_INFORMATION, *PBUSES_CONFIGURATION_INFORMATION; - + HANDLE RegistryMapKey; +} SCSI_BUS_INFO, *PSCSI_BUS_INFO; typedef struct _SCSI_PORT_INTERRUPT_DATA { @@ -201,16 +196,19 @@ typedef struct _SCSI_PORT_SAVE_INTERRUPT * SCSI_PORT_DEVICE_EXTENSION * * DESCRIPTION - * First part of the port objects device extension. The second - * part is the miniport-specific device extension. + * First part of the port objects device extension. The second + * part is the miniport-specific device extension. */ +// FDO typedef struct _SCSI_PORT_DEVICE_EXTENSION { + SCSI_PORT_COMMON_EXTENSION Common; + ULONG Length; ULONG MiniPortExtensionSize; PPORT_CONFIGURATION_INFORMATION PortConfig; - PBUSES_CONFIGURATION_INFORMATION BusesConfig; + PSCSI_BUS_INFO Buses; // children LUNs are stored here PVOID NonCachedExtension; ULONG PortNumber; @@ -218,7 +216,7 @@ typedef struct _SCSI_PORT_DEVICE_EXTENSION ULONG SrbFlags; ULONG Flags; - ULONG BusNum; + UCHAR NumberOfBuses; ULONG MaxTargedIds; ULONG MaxLunCount; @@ -238,7 +236,6 @@ typedef struct _SCSI_PORT_DEVICE_EXTENSION PMAPPED_ADDRESS MappedAddressList; ULONG LunExtensionSize; - PSCSI_PORT_LUN_EXTENSION LunExtensionList[LUS_NUMBER]; SCSI_PORT_INTERRUPT_DATA InterruptData; @@ -254,7 +251,6 @@ typedef struct _SCSI_PORT_DEVICE_EXTENSION IO_SCSI_CAPABILITIES PortCapabilities; - PDEVICE_OBJECT DeviceObject; PCONTROLLER_OBJECT ControllerObject; PHW_INITIALIZE HwInitialize; @@ -294,6 +290,11 @@ typedef struct _SCSI_PORT_DEVICE_EXTENSION ULONG InterruptCount; + UNICODE_STRING DeviceName; + UNICODE_STRING InterfaceName; + BOOLEAN DeviceStarted; + UINT8 TotalLUCount; + UCHAR MiniPortDeviceExtension[1]; /* must be the last entry */ } SCSI_PORT_DEVICE_EXTENSION, *PSCSI_PORT_DEVICE_EXTENSION; @@ -303,6 +304,42 @@ typedef struct _RESETBUS_PARAMS PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; } RESETBUS_PARAMS, *PRESETBUS_PARAMS; +typedef struct _SCSIPORT_DRIVER_EXTENSION +{ + PDRIVER_OBJECT DriverObject; + UNICODE_STRING RegistryPath; + BOOLEAN IsLegacyDriver; +} SCSI_PORT_DRIVER_EXTENSION, *PSCSI_PORT_DRIVER_EXTENSION; + +FORCEINLINE +BOOLEAN +VerifyIrpOutBufferSize( + _In_ PIRP Irp, + _In_ SIZE_T Size) +{ + PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp); + if (ioStack->Parameters.DeviceIoControl.OutputBufferLength < Size) + { + Irp->IoStatus.Information = Size; + return FALSE; + } + return TRUE; +} + +FORCEINLINE +BOOLEAN +VerifyIrpInBufferSize( + _In_ PIRP Irp, + _In_ SIZE_T Size) +{ + PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp); + if (ioStack->Parameters.DeviceIoControl.InputBufferLength < Size) + { + Irp->IoStatus.Information = Size; + return FALSE; + } + return TRUE; +} // ioctl.c @@ -315,25 +352,34 @@ ScsiPortDeviceControl( // fdo.c VOID -SpiScanAdapter( +FdoScanAdapter( _In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension); NTSTATUS -CallHWInitialize( +FdoCallHWInitialize( _In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension); -VOID -SpiCleanupAfterInit( +NTSTATUS +FdoRemoveAdapter( _In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension); +NTSTATUS +FdoStartAdapter( + _In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension); + +NTSTATUS +FdoDispatchPnp( + _In_ PDEVICE_OBJECT DeviceObject, + _Inout_ PIRP Irp); + // pdo.c -PSCSI_PORT_LUN_EXTENSION -SpiAllocateLunExtension( +PDEVICE_OBJECT +PdoCreateLunDevice( _In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension); PSCSI_PORT_LUN_EXTENSION -SpiGetLunExtension( +GetLunByPath( _In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, _In_ UCHAR PathId, _In_ UCHAR TargetId, @@ -342,22 +388,32 @@ SpiGetLunExtension( PSCSI_REQUEST_BLOCK_INFO SpiGetSrbData( _In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, - _In_ UCHAR PathId, - _In_ UCHAR TargetId, - _In_ UCHAR Lun, + _In_ PSCSI_PORT_LUN_EXTENSION LunExtension, _In_ UCHAR QueueTag); +NTSTATUS +PdoDispatchPnp( + _In_ PDEVICE_OBJECT DeviceObject, + _Inout_ PIRP Irp); + +// power.c + +DRIVER_DISPATCH ScsiPortDispatchPower; + // registry.c VOID SpiInitOpenKeys( _Inout_ PCONFIGURATION_INFO ConfigInfo, - _In_ PUNICODE_STRING RegistryPath); + _In_ PSCSI_PORT_DRIVER_EXTENSION DriverExtension); NTSTATUS -SpiBuildDeviceMap( - _In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, - _In_ PUNICODE_STRING RegistryPath); +RegistryInitAdapterKey( + _Inout_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension); + +NTSTATUS +RegistryInitLunKey( + _Inout_ PSCSI_PORT_LUN_EXTENSION LunExtension); // scsi.c diff --git a/drivers/storage/port/scsiport/scsitypes.h b/drivers/storage/port/scsiport/scsitypes.h new file mode 100644 index 00000000000..984c6db4e7a --- /dev/null +++ b/drivers/storage/port/scsiport/scsitypes.h @@ -0,0 +1,124 @@ + +// see https://docs.microsoft.com/en-us/windows-hardware/drivers/install/identifiers-for-scsi-devices +// and https://docs.microsoft.com/en-us/windows-hardware/drivers/install/identifiers-for-ide-devices + +FORCEINLINE +PCSTR +GetDeviceType( + _In_ PINQUIRYDATA InquiryData) +{ + switch (InquiryData->DeviceType) + { + case DIRECT_ACCESS_DEVICE: + return "Disk"; + case SEQUENTIAL_ACCESS_DEVICE: + return "Sequential"; + case PRINTER_DEVICE: + return "Printer"; + case PROCESSOR_DEVICE: + return "Processor"; + case WRITE_ONCE_READ_MULTIPLE_DEVICE: + return "Worm"; + case READ_ONLY_DIRECT_ACCESS_DEVICE: + return "CdRom"; + case SCANNER_DEVICE: + return "Scanner"; + case OPTICAL_DEVICE: + return "Optical"; + case MEDIUM_CHANGER: + return "Changer"; + case COMMUNICATION_DEVICE: + return "Net"; + case ARRAY_CONTROLLER_DEVICE: + return "Array"; + case SCSI_ENCLOSURE_DEVICE: + return "Enclosure"; + case REDUCED_BLOCK_DEVICE: + return "RBC"; + case OPTICAL_CARD_READER_WRITER_DEVICE: + return "CardReader"; + case BRIDGE_CONTROLLER_DEVICE: + return "Bridge"; + default: + return "Other"; + } +} + +FORCEINLINE +PCSTR +GetGenericType( + _In_ PINQUIRYDATA InquiryData) +{ + switch (InquiryData->DeviceType) + { + case DIRECT_ACCESS_DEVICE: + return "GenDisk"; + case PRINTER_DEVICE: + return "GenPrinter"; + case WRITE_ONCE_READ_MULTIPLE_DEVICE: + return "GenWorm"; + case READ_ONLY_DIRECT_ACCESS_DEVICE: + return "GenCdRom"; + case SCANNER_DEVICE: + return "GenScanner"; + case OPTICAL_DEVICE: + return "GenOptical"; + case MEDIUM_CHANGER: + return "ScsiChanger"; + case COMMUNICATION_DEVICE: + return "ScsiNet"; + case ARRAY_CONTROLLER_DEVICE: + return "ScsiArray"; + case SCSI_ENCLOSURE_DEVICE: + return "ScsiEnclosure"; + case REDUCED_BLOCK_DEVICE: + return "ScsiRBC"; + case OPTICAL_CARD_READER_WRITER_DEVICE: + return "ScsiCardReader"; + case BRIDGE_CONTROLLER_DEVICE: + return "ScsiBridge"; + default: + return "ScsiOther"; + } +} + +FORCEINLINE +PCWSTR +GetPeripheralTypeW( + _In_ PINQUIRYDATA InquiryData) +{ + switch (InquiryData->DeviceType) + { + case DIRECT_ACCESS_DEVICE: + return L"DiskPeripheral"; + case SEQUENTIAL_ACCESS_DEVICE: + return L"TapePeripheral"; + case PRINTER_DEVICE: + return L"PrinterPeripheral"; + // case 3: "ProcessorPeripheral", classified as 'other': fall back to default case. + case WRITE_ONCE_READ_MULTIPLE_DEVICE: + return L"WormPeripheral"; + case READ_ONLY_DIRECT_ACCESS_DEVICE: + return L"CdRomPeripheral"; + case SCANNER_DEVICE: + return L"ScannerPeripheral"; + case OPTICAL_DEVICE: + return L"OpticalDiskPeripheral"; + case MEDIUM_CHANGER: + return L"MediumChangerPeripheral"; + case COMMUNICATION_DEVICE: + return L"CommunicationsPeripheral"; + case ARRAY_CONTROLLER_DEVICE: + return L"ArrayPeripheral"; + case SCSI_ENCLOSURE_DEVICE: + return L"EnclosurePeripheral"; + case REDUCED_BLOCK_DEVICE: + return L"RBCPeripheral"; + case OPTICAL_CARD_READER_WRITER_DEVICE: + return L"CardReaderPeripheral"; + case BRIDGE_CONTROLLER_DEVICE: + return L"BridgePeripheral"; + default: + return L"OtherPeripheral"; + } +}