mirror of
https://github.com/reactos/reactos.git
synced 2024-07-10 14:45:06 +00:00
695 lines
23 KiB
C
695 lines
23 KiB
C
![]() |
/*
|
||
|
* PROJECT: ReactOS Storage Stack / SCSIPORT storage port library
|
||
|
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||
|
* PURPOSE: Adapter device object (FDO) support routines
|
||
|
* COPYRIGHT: Eric Kohl (eric.kohl@reactos.org)
|
||
|
* Aleksey Bragin (aleksey@reactos.org)
|
||
|
*/
|
||
|
|
||
|
#include "scsiport.h"
|
||
|
|
||
|
#define NDEBUG
|
||
|
#include <debug.h>
|
||
|
|
||
|
|
||
|
static
|
||
|
NTSTATUS
|
||
|
SpiSendInquiry(
|
||
|
_In_ PDEVICE_OBJECT DeviceObject,
|
||
|
_Inout_ PSCSI_LUN_INFO LunInfo)
|
||
|
{
|
||
|
IO_STATUS_BLOCK IoStatusBlock;
|
||
|
PIO_STACK_LOCATION IrpStack;
|
||
|
KEVENT Event;
|
||
|
KIRQL Irql;
|
||
|
PIRP Irp;
|
||
|
NTSTATUS Status;
|
||
|
PINQUIRYDATA InquiryBuffer;
|
||
|
PSENSE_DATA SenseBuffer;
|
||
|
BOOLEAN KeepTrying = TRUE;
|
||
|
ULONG RetryCount = 0;
|
||
|
SCSI_REQUEST_BLOCK Srb;
|
||
|
PCDB Cdb;
|
||
|
PSCSI_PORT_LUN_EXTENSION LunExtension;
|
||
|
PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
|
||
|
|
||
|
DPRINT("SpiSendInquiry() called\n");
|
||
|
|
||
|
DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||
|
|
||
|
InquiryBuffer = ExAllocatePoolWithTag(NonPagedPool, INQUIRYDATABUFFERSIZE, TAG_SCSIPORT);
|
||
|
if (InquiryBuffer == NULL)
|
||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
|
||
|
SenseBuffer = ExAllocatePoolWithTag(NonPagedPool, SENSE_BUFFER_SIZE, TAG_SCSIPORT);
|
||
|
if (SenseBuffer == NULL)
|
||
|
{
|
||
|
ExFreePoolWithTag(InquiryBuffer, TAG_SCSIPORT);
|
||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
}
|
||
|
|
||
|
while (KeepTrying)
|
||
|
{
|
||
|
/* Initialize event for waiting */
|
||
|
KeInitializeEvent(&Event,
|
||
|
NotificationEvent,
|
||
|
FALSE);
|
||
|
|
||
|
/* Create an IRP */
|
||
|
Irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_IN,
|
||
|
DeviceObject,
|
||
|
NULL,
|
||
|
0,
|
||
|
InquiryBuffer,
|
||
|
INQUIRYDATABUFFERSIZE,
|
||
|
TRUE,
|
||
|
&Event,
|
||
|
&IoStatusBlock);
|
||
|
if (Irp == NULL)
|
||
|
{
|
||
|
DPRINT("IoBuildDeviceIoControlRequest() failed\n");
|
||
|
|
||
|
/* Quit the loop */
|
||
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
KeepTrying = FALSE;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
/* Prepare SRB */
|
||
|
RtlZeroMemory(&Srb, sizeof(SCSI_REQUEST_BLOCK));
|
||
|
|
||
|
Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
|
||
|
Srb.OriginalRequest = Irp;
|
||
|
Srb.PathId = LunInfo->PathId;
|
||
|
Srb.TargetId = LunInfo->TargetId;
|
||
|
Srb.Lun = LunInfo->Lun;
|
||
|
Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
|
||
|
Srb.SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
|
||
|
Srb.TimeOutValue = 4;
|
||
|
Srb.CdbLength = 6;
|
||
|
|
||
|
Srb.SenseInfoBuffer = SenseBuffer;
|
||
|
Srb.SenseInfoBufferLength = SENSE_BUFFER_SIZE;
|
||
|
|
||
|
Srb.DataBuffer = InquiryBuffer;
|
||
|
Srb.DataTransferLength = INQUIRYDATABUFFERSIZE;
|
||
|
|
||
|
/* Attach Srb to the Irp */
|
||
|
IrpStack = IoGetNextIrpStackLocation (Irp);
|
||
|
IrpStack->Parameters.Scsi.Srb = &Srb;
|
||
|
|
||
|
/* Fill in CDB */
|
||
|
Cdb = (PCDB)Srb.Cdb;
|
||
|
Cdb->CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY;
|
||
|
Cdb->CDB6INQUIRY.LogicalUnitNumber = LunInfo->Lun;
|
||
|
Cdb->CDB6INQUIRY.AllocationLength = INQUIRYDATABUFFERSIZE;
|
||
|
|
||
|
/* Call the driver */
|
||
|
Status = IoCallDriver(DeviceObject, Irp);
|
||
|
|
||
|
/* Wait for it to complete */
|
||
|
if (Status == STATUS_PENDING)
|
||
|
{
|
||
|
DPRINT("SpiSendInquiry(): Waiting for the driver to process request...\n");
|
||
|
KeWaitForSingleObject(&Event,
|
||
|
Executive,
|
||
|
KernelMode,
|
||
|
FALSE,
|
||
|
NULL);
|
||
|
Status = IoStatusBlock.Status;
|
||
|
}
|
||
|
|
||
|
DPRINT("SpiSendInquiry(): 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,
|
||
|
InquiryBuffer,
|
||
|
INQUIRYDATABUFFERSIZE);
|
||
|
|
||
|
/* Quit the loop */
|
||
|
Status = STATUS_SUCCESS;
|
||
|
KeepTrying = FALSE;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
DPRINT("Inquiry SRB failed with SrbStatus 0x%08X\n", Srb.SrbStatus);
|
||
|
|
||
|
/* Check if the queue is frozen */
|
||
|
if (Srb.SrbStatus & SRB_STATUS_QUEUE_FROZEN)
|
||
|
{
|
||
|
/* 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);
|
||
|
|
||
|
/* Clear frozen flag */
|
||
|
LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE;
|
||
|
|
||
|
/* Acquire the spinlock */
|
||
|
KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
|
||
|
|
||
|
/* Process the request */
|
||
|
SpiGetNextRequestFromLun(DeviceObject->DeviceExtension, LunExtension);
|
||
|
|
||
|
/* SpiGetNextRequestFromLun() releases the spinlock,
|
||
|
so we just lower irql back to what it was before */
|
||
|
KeLowerIrql(Irql);
|
||
|
}
|
||
|
|
||
|
/* Check if data overrun happened */
|
||
|
if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN)
|
||
|
{
|
||
|
DPRINT("Data overrun at TargetId %d\n", LunInfo->TargetId);
|
||
|
|
||
|
/* Nothing dramatic, just copy data, but limiting the size */
|
||
|
RtlCopyMemory(LunInfo->InquiryData,
|
||
|
InquiryBuffer,
|
||
|
(Srb.DataTransferLength > INQUIRYDATABUFFERSIZE) ?
|
||
|
INQUIRYDATABUFFERSIZE : Srb.DataTransferLength);
|
||
|
|
||
|
/* Quit the loop */
|
||
|
Status = STATUS_SUCCESS;
|
||
|
KeepTrying = FALSE;
|
||
|
}
|
||
|
else if ((Srb.SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
|
||
|
SenseBuffer->SenseKey == SCSI_SENSE_ILLEGAL_REQUEST)
|
||
|
{
|
||
|
/* LUN is not valid, but some device responds there.
|
||
|
Mark it as invalid anyway */
|
||
|
|
||
|
/* Quit the loop */
|
||
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
||
|
KeepTrying = FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* Retry a couple of times if no timeout happened */
|
||
|
if ((RetryCount < 2) &&
|
||
|
(SRB_STATUS(Srb.SrbStatus) != SRB_STATUS_NO_DEVICE) &&
|
||
|
(SRB_STATUS(Srb.SrbStatus) != SRB_STATUS_SELECTION_TIMEOUT))
|
||
|
{
|
||
|
RetryCount++;
|
||
|
KeepTrying = TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* That's all, quit the loop */
|
||
|
KeepTrying = FALSE;
|
||
|
|
||
|
/* Set status according to SRB status */
|
||
|
if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_BAD_FUNCTION ||
|
||
|
SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_BAD_SRB_BLOCK_LENGTH)
|
||
|
{
|
||
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Status = STATUS_IO_DEVICE_ERROR;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Free buffers */
|
||
|
ExFreePoolWithTag(InquiryBuffer, TAG_SCSIPORT);
|
||
|
ExFreePoolWithTag(SenseBuffer, TAG_SCSIPORT);
|
||
|
|
||
|
DPRINT("SpiSendInquiry() done with Status 0x%08X\n", Status);
|
||
|
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
/* Scans all SCSI buses */
|
||
|
VOID
|
||
|
SpiScanAdapter(
|
||
|
_In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
|
||
|
{
|
||
|
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;
|
||
|
|
||
|
DPRINT("SpiScanAdapter() called\n");
|
||
|
|
||
|
/* Scan all buses */
|
||
|
for (Bus = 0; Bus < DeviceExtension->BusNum; Bus++)
|
||
|
{
|
||
|
DPRINT(" Scanning bus %d\n", Bus);
|
||
|
DevicesFound = 0;
|
||
|
|
||
|
/* 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);
|
||
|
|
||
|
/* And send INQUIRY to every target */
|
||
|
for (Target = 0; Target < DeviceExtension->PortConfig->MaximumNumberOfTargets; Target++)
|
||
|
{
|
||
|
/* 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)
|
||
|
continue;
|
||
|
|
||
|
/* Scan all logical units */
|
||
|
for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++)
|
||
|
{
|
||
|
if ((!LunExtension) || (!LunInfo))
|
||
|
break;
|
||
|
|
||
|
/* 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)
|
||
|
{
|
||
|
RtlZeroMemory(LunExtension + 1,
|
||
|
DeviceExtension->LunExtensionSize);
|
||
|
}
|
||
|
|
||
|
/* Finally send the inquiry command */
|
||
|
Status = SpiSendInquiry(DeviceExtension->DeviceObject, LunInfo);
|
||
|
|
||
|
if (NT_SUCCESS(Status))
|
||
|
{
|
||
|
/* Let's see if we really found a device */
|
||
|
PINQUIRYDATA InquiryData = (PINQUIRYDATA)LunInfo->InquiryData;
|
||
|
|
||
|
/* Check if this device is unsupported */
|
||
|
if (InquiryData->DeviceTypeQualifier == DEVICE_QUALIFIER_NOT_SUPPORTED)
|
||
|
{
|
||
|
DeviceExtension->LunExtensionList[Hint] =
|
||
|
DeviceExtension->LunExtensionList[Hint]->Next;
|
||
|
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
/* Clear the "in scan" flag */
|
||
|
LunExtension->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);
|
||
|
|
||
|
/*
|
||
|
* 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);
|
||
|
|
||
|
/* Add this info to the linked list */
|
||
|
LunInfo->Next = NULL;
|
||
|
if (LastLunInfo)
|
||
|
LastLunInfo->Next = LunInfo;
|
||
|
else
|
||
|
BusScanInfo->LunInfo = LunInfo;
|
||
|
|
||
|
/* 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++;
|
||
|
}
|
||
|
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)
|
||
|
continue;
|
||
|
else
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* 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");
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Calls HwInitialize routine of the miniport and sets up interrupts
|
||
|
* Should be called inside ScsiPortInitialize (for legacy drivers)
|
||
|
* or inside IRP_MN_START_DEVICE for pnp drivers
|
||
|
*
|
||
|
* @param[in] DeviceExtension The device extension
|
||
|
*
|
||
|
* @return NTSTATUS of the operation
|
||
|
*/
|
||
|
NTSTATUS
|
||
|
CallHWInitialize(
|
||
|
_In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
|
||
|
{
|
||
|
PPORT_CONFIGURATION_INFORMATION PortConfig = DeviceExtension->PortConfig;
|
||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
KIRQL OldIrql;
|
||
|
|
||
|
/* Deal with interrupts */
|
||
|
if (DeviceExtension->HwInterrupt == NULL ||
|
||
|
(PortConfig->BusInterruptLevel == 0 && PortConfig->BusInterruptVector == 0))
|
||
|
{
|
||
|
/* No interrupts */
|
||
|
DeviceExtension->InterruptCount = 0;
|
||
|
|
||
|
DPRINT1("Interrupt Count: 0\n");
|
||
|
|
||
|
UNIMPLEMENTED;
|
||
|
|
||
|
/* This code path will ALWAYS crash so stop it now */
|
||
|
__debugbreak();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
BOOLEAN InterruptShareable;
|
||
|
KINTERRUPT_MODE InterruptMode[2];
|
||
|
ULONG InterruptVector[2], i, MappedIrq[2];
|
||
|
KIRQL Dirql[2], MaxDirql;
|
||
|
KAFFINITY Affinity[2];
|
||
|
|
||
|
DeviceExtension->InterruptLevel[0] = PortConfig->BusInterruptLevel;
|
||
|
DeviceExtension->InterruptLevel[1] = PortConfig->BusInterruptLevel2;
|
||
|
|
||
|
InterruptVector[0] = PortConfig->BusInterruptVector;
|
||
|
InterruptVector[1] = PortConfig->BusInterruptVector2;
|
||
|
|
||
|
InterruptMode[0] = PortConfig->InterruptMode;
|
||
|
InterruptMode[1] = PortConfig->InterruptMode2;
|
||
|
|
||
|
DeviceExtension->InterruptCount =
|
||
|
(PortConfig->BusInterruptLevel2 != 0 ||
|
||
|
PortConfig->BusInterruptVector2 != 0) ? 2 : 1;
|
||
|
|
||
|
for (i = 0; i < DeviceExtension->InterruptCount; i++)
|
||
|
{
|
||
|
/* Register an interrupt handler for this device */
|
||
|
MappedIrq[i] = HalGetInterruptVector(
|
||
|
PortConfig->AdapterInterfaceType, PortConfig->SystemIoBusNumber,
|
||
|
DeviceExtension->InterruptLevel[i], InterruptVector[i], &Dirql[i],
|
||
|
&Affinity[i]);
|
||
|
}
|
||
|
|
||
|
if (DeviceExtension->InterruptCount == 1 || Dirql[0] > Dirql[1])
|
||
|
MaxDirql = Dirql[0];
|
||
|
else
|
||
|
MaxDirql = Dirql[1];
|
||
|
|
||
|
for (i = 0; i < DeviceExtension->InterruptCount; i++)
|
||
|
{
|
||
|
/* Determine IRQ sharability as usual */
|
||
|
if (PortConfig->AdapterInterfaceType == MicroChannel ||
|
||
|
InterruptMode[i] == LevelSensitive)
|
||
|
{
|
||
|
InterruptShareable = TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
InterruptShareable = FALSE;
|
||
|
}
|
||
|
|
||
|
Status = IoConnectInterrupt(
|
||
|
&DeviceExtension->Interrupt[i], (PKSERVICE_ROUTINE)ScsiPortIsr, DeviceExtension,
|
||
|
&DeviceExtension->IrqLock, MappedIrq[i], Dirql[i], MaxDirql, InterruptMode[i],
|
||
|
InterruptShareable, Affinity[i], FALSE);
|
||
|
|
||
|
if (!(NT_SUCCESS(Status)))
|
||
|
{
|
||
|
DPRINT1("Could not connect interrupt %d\n", InterruptVector[i]);
|
||
|
DeviceExtension->Interrupt[i] = NULL;
|
||
|
return Status;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!NT_SUCCESS(Status))
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
/* Save IoAddress (from access ranges) */
|
||
|
if (PortConfig->NumberOfAccessRanges != 0)
|
||
|
{
|
||
|
DeviceExtension->IoAddress = ((*(PortConfig->AccessRanges))[0]).RangeStart.LowPart;
|
||
|
|
||
|
DPRINT("Io Address %x\n", DeviceExtension->IoAddress);
|
||
|
}
|
||
|
|
||
|
/* Set flag that it's allowed to disconnect during this command */
|
||
|
DeviceExtension->Flags |= SCSI_PORT_DISCONNECT_ALLOWED;
|
||
|
|
||
|
/* Initialize counter of active requests (-1 means there are none) */
|
||
|
DeviceExtension->ActiveRequestCounter = -1;
|
||
|
|
||
|
/* Analyze what we have about DMA */
|
||
|
if (DeviceExtension->AdapterObject != NULL && PortConfig->Master &&
|
||
|
PortConfig->NeedPhysicalAddresses)
|
||
|
{
|
||
|
DeviceExtension->MapRegisters = TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DeviceExtension->MapRegisters = FALSE;
|
||
|
}
|
||
|
|
||
|
/* Call HwInitialize at DISPATCH_LEVEL */
|
||
|
KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
|
||
|
|
||
|
if (!KeSynchronizeExecution(
|
||
|
DeviceExtension->Interrupt[0], DeviceExtension->HwInitialize,
|
||
|
DeviceExtension->MiniPortDeviceExtension))
|
||
|
{
|
||
|
DPRINT1("HwInitialize() failed!\n");
|
||
|
KeLowerIrql(OldIrql);
|
||
|
return STATUS_ADAPTER_HARDWARE_ERROR;
|
||
|
}
|
||
|
|
||
|
/* Check if a notification is needed */
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
/* Lower irql back to what it was */
|
||
|
KeLowerIrql(OldIrql);
|
||
|
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
SpiCleanupAfterInit(
|
||
|
_In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
|
||
|
{
|
||
|
PSCSI_LUN_INFO LunInfo;
|
||
|
PVOID Ptr;
|
||
|
ULONG Bus, Lun;
|
||
|
|
||
|
/* Check if we have something to clean up */
|
||
|
if (DeviceExtension == NULL)
|
||
|
return;
|
||
|
|
||
|
/* Stop the timer */
|
||
|
IoStopTimer(DeviceExtension->DeviceObject);
|
||
|
|
||
|
/* Disconnect the interrupts */
|
||
|
while (DeviceExtension->InterruptCount)
|
||
|
{
|
||
|
if (DeviceExtension->Interrupt[--DeviceExtension->InterruptCount])
|
||
|
IoDisconnectInterrupt(DeviceExtension->Interrupt[DeviceExtension->InterruptCount]);
|
||
|
}
|
||
|
|
||
|
/* Delete ConfigInfo */
|
||
|
if (DeviceExtension->BusesConfig)
|
||
|
{
|
||
|
for (Bus = 0; Bus < DeviceExtension->BusNum; Bus++)
|
||
|
{
|
||
|
if (!DeviceExtension->BusesConfig->BusScanInfo[Bus])
|
||
|
continue;
|
||
|
|
||
|
LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus]->LunInfo;
|
||
|
|
||
|
while (LunInfo)
|
||
|
{
|
||
|
/* Free current, but save pointer to the next one */
|
||
|
Ptr = LunInfo->Next;
|
||
|
ExFreePool(LunInfo);
|
||
|
LunInfo = Ptr;
|
||
|
}
|
||
|
|
||
|
ExFreePool(DeviceExtension->BusesConfig->BusScanInfo[Bus]);
|
||
|
}
|
||
|
|
||
|
ExFreePool(DeviceExtension->BusesConfig);
|
||
|
}
|
||
|
|
||
|
/* 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);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Free common buffer (if it exists) */
|
||
|
if (DeviceExtension->SrbExtensionBuffer != NULL &&
|
||
|
DeviceExtension->CommonBufferLength != 0)
|
||
|
{
|
||
|
if (!DeviceExtension->AdapterObject)
|
||
|
{
|
||
|
ExFreePool(DeviceExtension->SrbExtensionBuffer);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
HalFreeCommonBuffer(DeviceExtension->AdapterObject,
|
||
|
DeviceExtension->CommonBufferLength,
|
||
|
DeviceExtension->PhysicalAddress,
|
||
|
DeviceExtension->SrbExtensionBuffer,
|
||
|
FALSE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Free SRB info */
|
||
|
if (DeviceExtension->SrbInfo != NULL)
|
||
|
ExFreePool(DeviceExtension->SrbInfo);
|
||
|
|
||
|
/* Unmap mapped addresses */
|
||
|
while (DeviceExtension->MappedAddressList != NULL)
|
||
|
{
|
||
|
MmUnmapIoSpace(DeviceExtension->MappedAddressList->MappedAddress,
|
||
|
DeviceExtension->MappedAddressList->NumberOfBytes);
|
||
|
|
||
|
Ptr = DeviceExtension->MappedAddressList;
|
||
|
DeviceExtension->MappedAddressList = DeviceExtension->MappedAddressList->NextMappedAddress;
|
||
|
|
||
|
ExFreePool(Ptr);
|
||
|
}
|
||
|
|
||
|
/* Finally delete the device object */
|
||
|
DPRINT("Deleting device %p\n", DeviceExtension->DeviceObject);
|
||
|
IoDeleteDevice(DeviceExtension->DeviceObject);
|
||
|
}
|