Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

5637 lines
120 KiB

/*++
Copyright (c) 1994 Microsoft Corporation
Module Name:
diskdump.c
Abstract:
This is a special SCSI driver that serves as a combined SCSI disk
class driver and SCSI manager for SCSI miniport drivers. It's sole
responsibility is to provide disk services to copy physical memory
into a portion of the disk as a record of a system crash.
Author:
Mike Glass
Notes:
Ported from osloader SCSI modules which were originally developed by
Jeff Havens and Mike Glass.
Revision History:
--*/
#include "ntosp.h"
#include "stdarg.h"
#include "stdio.h"
#include "storport.h"
#include "ntdddisk.h"
#include "diskdump.h"
//
// Need a couple of aliases since we build w/ storport.h vs srb.h.
//
enum {
CallDisableInterrupts = _obsolete1,
CallEnableInterrupts = _obsolete2
};
typedef PHYSICAL_ADDRESS SCSI_PHYSICAL_ADDRESS, *PSCSI_PHYSICAL_ADDRESS;
#undef ScsiPortConvertPhysicalAddressToUlong
#if DBG
#undef DebugPrint
#define DebugPrint(x) ScsiDebugPrint x
#endif
extern PBOOLEAN Mm64BitPhysicalAddress;
//
// The scsi dump driver needs to allocate memory out of it's own, private
// allocation pool. This necessary to prevent pool corruption from
// preventing a successful crashdump.
//
#ifdef ExAllocatePool
#undef ExAllocatePool
#endif
#ifdef ExFreePool
#undef ExFreePool
#endif
#define ExAllocatePool C_ASSERT (FALSE)
#define ExFreePool C_ASSERT (FALSE)
PDEVICE_EXTENSION DeviceExtension;
#define SECONDS (1000 * 1000)
#define RESET_DELAY (4 * SECONDS)
typedef
BOOLEAN
(*PSTOR_SYNCHRONIZED_ACCESS)(
IN PVOID HwDeviceExtension,
IN PVOID Context
);
VOID
ExecuteSrb(
IN PSCSI_REQUEST_BLOCK Srb
);
BOOLEAN
ResetBus(
IN PDEVICE_EXTENSION pDevExt,
IN ULONG PathId
);
VOID
FreeScatterGatherList(
IN PDEVICE_EXTENSION DeviceExtension,
IN PSCSI_REQUEST_BLOCK Srb
);
ULONG
ScsiPortConvertPhysicalAddressToUlong(
PHYSICAL_ADDRESS Address
);
VOID
ScsiDebugPrint(
ULONG DebugPrintLevel,
PCCHAR DebugMessage,
...
);
//
// Routines start
//
VOID
FreePool(
IN PVOID Ptr
)
/*++
Routine Description:
free block of memory.
Arguments:
ptr - The memory to free.
Return Value:
None.
--*/
{
PMEMORY_HEADER freedBlock;
//
// Don't try to coalesce. They will probably just ask for something
// of just this size again.
//
freedBlock = (PMEMORY_HEADER)Ptr - 1;
freedBlock->Next = DeviceExtension->FreeMemory;
DeviceExtension->FreeMemory = freedBlock;
}
PVOID
AllocatePool(
IN ULONG Size
)
/*++
Routine Description:
Allocate block of memory. Uses first fit algorithm.
The free memory pointer always points to the beginning of the zone.
Arguments:
Size - size of memory to be allocated.
Return Value:
Address of memory block.
--*/
{
PMEMORY_HEADER descriptor = DeviceExtension->FreeMemory;
PMEMORY_HEADER previous = NULL;
ULONG length;
//
// Adjust size for memory header and round up memory to 16 bytes.
//
length = (Size + sizeof(MEMORY_HEADER) + 15) & ~15;
//
// Walk free list looking for first block of memory equal to
// or greater than (adjusted) size requested.
//
while (descriptor) {
if (descriptor->Length >= length) {
//
// Update free list eliminating as much of this block as necessary.
//
// Make sure if we don't have enough of the block left for a
// memory header we just point to the next block (and adjust
// length accordingly).
//
if (!previous) {
if (descriptor->Length < (length+sizeof(MEMORY_HEADER))) {
DeviceExtension->FreeMemory = DeviceExtension->FreeMemory->Next;
} else {
DeviceExtension->FreeMemory =
(PMEMORY_HEADER)((PUCHAR)descriptor + length);
previous = DeviceExtension->FreeMemory;
previous->Length = descriptor->Length - length;
previous->Next = descriptor->Next;
descriptor->Length = length;
}
} else {
if (descriptor->Length < (length+sizeof(MEMORY_HEADER))) {
previous->Next = descriptor->Next;
} else {
previous->Next =
(PMEMORY_HEADER)((PUCHAR)descriptor + length);
previous->Next->Length = descriptor->Length - length;
previous->Next->Next = descriptor->Next;
descriptor->Length = length;
}
}
//
// Update memory header for allocated block.
//
descriptor->Next = NULL;
//
// Adjust address past header.
//
(PUCHAR)descriptor += sizeof(MEMORY_HEADER);
break;
}
previous = descriptor;
descriptor = descriptor->Next;
}
return descriptor;
}
BOOLEAN
DiskDumpOpen(
IN LARGE_INTEGER PartitionOffset
)
/*++
Routine Description:
This is the entry point for open requests to the diskdump driver.
Arguments:
PartitionOffset - Byte offset of partition on disk.
Return Value:
TRUE
--*/
{
//
// Update partition object in device extension for this partition.
//
DeviceExtension->PartitionOffset = PartitionOffset;
return TRUE;
}
VOID
WorkHorseDpc(
)
/*++
Routine Description:
Handle miniport notification.
Arguments:
None.
Return Value:
None.
--*/
{
PSCSI_REQUEST_BLOCK srb = &DeviceExtension->Srb;
//
// Check for a flush DMA adapter object request. Note that
// on the finish up code this will have been already cleared.
//
if (DeviceExtension->InterruptFlags & PD_FLUSH_ADAPTER_BUFFERS) {
//
// Call IoFlushAdapterBuffers using the parameters saved from the last
// IoMapTransfer call.
//
IoFlushAdapterBuffers(
DeviceExtension->DmaAdapterObject,
DeviceExtension->Mdl,
DeviceExtension->MapRegisterBase[1],
DeviceExtension->FlushAdapterParameters.LogicalAddress,
DeviceExtension->FlushAdapterParameters.Length,
(BOOLEAN)(DeviceExtension->FlushAdapterParameters.Srb->SrbFlags
& SRB_FLAGS_DATA_OUT ? TRUE : FALSE));
DeviceExtension->InterruptFlags &= ~PD_FLUSH_ADAPTER_BUFFERS;
}
//
// Check for an IoMapTransfer DMA request. Note that on the finish
// up code, this will have been cleared.
//
if (DeviceExtension->InterruptFlags & PD_MAP_TRANSFER) {
//
// Call IoMapTransfer using the parameters saved from the
// interrupt level.
//
IoMapTransfer(
DeviceExtension->DmaAdapterObject,
DeviceExtension->Mdl,
DeviceExtension->MapRegisterBase[1],
DeviceExtension->MapTransferParameters.LogicalAddress,
&DeviceExtension->MapTransferParameters.Length,
(BOOLEAN)(DeviceExtension->MapTransferParameters.Srb->SrbFlags
& SRB_FLAGS_DATA_OUT ? TRUE : FALSE));
//
// Save the paramters for IoFlushAdapterBuffers.
//
DeviceExtension->FlushAdapterParameters =
DeviceExtension->MapTransferParameters;
DeviceExtension->InterruptFlags &= ~PD_MAP_TRANSFER;
DeviceExtension->Flags |= PD_CALL_DMA_STARTED;
}
//
// Process any completed requests.
//
if (DeviceExtension->RequestComplete) {
//
// Reset request timeout counter.
//
DeviceExtension->RequestTimeoutCounter = -1;
DeviceExtension->RequestComplete = FALSE;
DeviceExtension->RequestPending = FALSE;
//
// Flush the adapter buffers if necessary.
//
if (DeviceExtension->MasterWithAdapter) {
FreeScatterGatherList (DeviceExtension, srb);
}
if (srb->SrbStatus != SRB_STATUS_SUCCESS) {
if ( ((srb->ScsiStatus == SCSISTAT_BUSY) ||
(srb->SrbStatus == SRB_STATUS_BUSY) )&&
(DeviceExtension->RetryCount++ < 20)) {
//
// If busy status is returned, then indicate that the logical
// unit is busy. The timeout code will restart the request
// when it fires. Reset the status to pending.
//
srb->SrbStatus = SRB_STATUS_PENDING;
DeviceExtension->Flags |= PD_LOGICAL_UNIT_IS_BUSY;
//
// Restore the data transfer length.
//
srb->DataTransferLength = DeviceExtension->ByteCount;
DeviceExtension->RequestPending = TRUE;
}
}
//
// Make MDL pointer NULL to show there is no outstanding request.
//
DeviceExtension->Mdl = NULL;
}
}
VOID
RequestSenseCompletion(
)
/*++
Routine Description:
Arguments:
None.
Return Value:
None.
--*/
{
PSCSI_REQUEST_BLOCK srb = &DeviceExtension->RequestSenseSrb;
PSCSI_REQUEST_BLOCK failingSrb = &DeviceExtension->Srb;
PSENSE_DATA senseBuffer = DeviceExtension->RequestSenseBuffer;
//
// Request sense completed. If successful or data over/underrun
// get the failing SRB and indicate that the sense information
// is valid. The class driver will check for underrun and determine
// if there is enough sense information to be useful.
//
if ((SRB_STATUS(srb->SrbStatus) == SRB_STATUS_SUCCESS) ||
(SRB_STATUS(srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN)) {
//
// Check that request sense buffer is valid.
//
if (srb->DataTransferLength >= FIELD_OFFSET(SENSE_DATA, CommandSpecificInformation)) {
DebugPrint((1,"RequestSenseCompletion: Error code is %x\n",
senseBuffer->ErrorCode));
DebugPrint((1,"RequestSenseCompletion: Sense key is %x\n",
senseBuffer->SenseKey));
DebugPrint((1, "RequestSenseCompletion: Additional sense code is %x\n",
senseBuffer->AdditionalSenseCode));
DebugPrint((1, "RequestSenseCompletion: Additional sense code qualifier is %x\n",
senseBuffer->AdditionalSenseCodeQualifier));
}
}
//
// Complete original request.
//
DeviceExtension->RequestComplete = TRUE;
WorkHorseDpc();
}
VOID
IssueRequestSense(
)
/*++
Routine Description:
This routine creates a REQUEST SENSE request and sends it to the miniport
driver.
The completion routine cleans up the data structures
and processes the logical unit queue according to the flags.
A pointer to failing SRB is stored at the end of the request sense
Srb, so that the completion routine can find it.
Arguments:
None.
Return Value:
None.
--*/
{
PSCSI_REQUEST_BLOCK srb = &DeviceExtension->RequestSenseSrb;
PCDB cdb = (PCDB)srb->Cdb;
PPFN_NUMBER page;
PFN_NUMBER localMdl[ (sizeof(MDL)/sizeof(PFN_NUMBER)) + (MAXIMUM_TRANSFER_SIZE / PAGE_SIZE) + 2];
//
// Zero SRB.
//
RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
//
// Build REQUEST SENSE SRB.
//
srb->TargetId = DeviceExtension->Srb.TargetId;
srb->Lun = DeviceExtension->Srb.Lun;
srb->PathId = DeviceExtension->Srb.PathId;
srb->Length = sizeof(SCSI_REQUEST_BLOCK);
srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
srb->DataBuffer = DeviceExtension->RequestSenseBuffer;
srb->DataTransferLength = sizeof(SENSE_DATA);
srb->ScsiStatus = srb->SrbStatus = 0;
srb->NextSrb = 0;
srb->CdbLength = 6;
srb->TimeOutValue = 5;
//
// Build MDL and map it so that it can be used.
//
DeviceExtension->Mdl = (PMDL) &localMdl[0];
MmInitializeMdl(DeviceExtension->Mdl,
srb->DataBuffer,
srb->DataTransferLength);
page = MmGetMdlPfnArray ( DeviceExtension->Mdl );
*page = (PFN_NUMBER)(DeviceExtension->PhysicalAddress[1].QuadPart >> PAGE_SHIFT);
MmMapMemoryDumpMdl(DeviceExtension->Mdl);
//
// Disable auto request sense.
//
srb->SenseInfoBufferLength = 0;
srb->SenseInfoBuffer = NULL;
//
// Set read and bypass frozen queue bits in flags.
//
srb->SrbFlags = SRB_FLAGS_DATA_IN |
SRB_FLAGS_BYPASS_FROZEN_QUEUE |
SRB_FLAGS_DISABLE_SYNCH_TRANSFER |
SRB_FLAGS_DISABLE_AUTOSENSE |
SRB_FLAGS_DISABLE_DISCONNECT;
//
// REQUEST SENSE cdb looks like INQUIRY cdb.
//
cdb->CDB6INQUIRY.OperationCode = SCSIOP_REQUEST_SENSE;
cdb->CDB6INQUIRY.AllocationLength = sizeof(SENSE_DATA);
//
// Send SRB to miniport driver.
//
ExecuteSrb(srb);
}
ULONG
StartDevice(
IN UCHAR TargetId,
IN UCHAR Lun
)
/*++
Routine Description:
Starts up the target device.
Arguments:
TargetId - the id of the device
Lun - The logical unit number
Return Value:
SRB status
--*/
{
PSCSI_REQUEST_BLOCK srb = &DeviceExtension->RequestSenseSrb;
PCDB cdb = (PCDB)srb->Cdb;
ULONG retry;
retry = 0;
DebugPrint((1,"StartDevice: Attempt to start device\n"));
retry_start:
//
// Zero SRB.
//
RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
RtlZeroMemory(cdb, sizeof(CDB));
srb->TargetId = TargetId;
srb->Lun = Lun;
srb->PathId = DeviceExtension->Srb.PathId;
srb->Length = sizeof(SCSI_REQUEST_BLOCK);
srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER |
SRB_FLAGS_DISABLE_AUTOSENSE |
SRB_FLAGS_DISABLE_SYNCH_TRANSFER |
SRB_FLAGS_BYPASS_LOCKED_QUEUE;
srb->CdbLength = 6;
srb->SrbStatus = 0;
srb->ScsiStatus = 0;
srb->NextSrb = 0;
srb->TimeOutValue = 30;
cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
cdb->START_STOP.Start = 1;
//
// Send SRB to miniport driver.
//
ExecuteSrb(srb);
if (srb->SrbStatus != SRB_STATUS_SUCCESS) {
if (retry++ < 4) {
DebugPrint((1,"StartDevice: Failed SRB STATUS: %x Retry #: %x\n",
srb->SrbStatus,retry));
goto retry_start;
}
}
return srb->SrbStatus;
}
VOID
AllocateScatterGatherList(
IN PDEVICE_EXTENSION DeviceExtension,
IN PSCSI_REQUEST_BLOCK Srb
)
/*++
Routine Description:
Create a scatter/gather list for the specified IO.
Arguments:
DeviceExtension - Device extension.
Srb - Scsi Request block to create the scatter/gather list for.
Return Value:
None.
--*/
{
BOOLEAN succ;
BOOLEAN writeToDevice;
ULONG totalLength;
PSCATTER_GATHER_ELEMENT scatterList;
//
// Calculate the number of map registers needed for this transfer.
//
DeviceExtension->NumberOfMapRegisters =
ADDRESS_AND_SIZE_TO_SPAN_PAGES(Srb->DataBuffer,
Srb->DataTransferLength);
//
// Build the scatter/gather list.
//
scatterList = DeviceExtension->ScatterGatherList.Elements;
totalLength = 0;
DeviceExtension->ScatterGatherList.NumberOfElements = 0;
//
// Build the scatter/gather list by looping through the transfer
// calling I/O map transfer.
//
writeToDevice = Srb->SrbFlags & SRB_FLAGS_DATA_OUT ? TRUE : FALSE;
while (totalLength < Srb->DataTransferLength) {
//
// Request that the rest of the transfer be mapped.
//
scatterList->Length = Srb->DataTransferLength - totalLength;
//
// Io is always done through the second map register.
//
scatterList->Address =
IoMapTransfer (
DeviceExtension->DmaAdapterObject,
DeviceExtension->Mdl,
DeviceExtension->MapRegisterBase[1],
(PCCHAR) Srb->DataBuffer + totalLength,
&scatterList->Length,
writeToDevice);
totalLength += scatterList->Length;
scatterList++;
DeviceExtension->ScatterGatherList.NumberOfElements++;
}
}
VOID
FreeScatterGatherList(
IN PDEVICE_EXTENSION DeviceExtension,
IN PSCSI_REQUEST_BLOCK Srb
)
/*++
Routine Description:
Free a scatter/gather list, freeing all resources associated with it.
Arguments:
DeviceExtension - Device extension.
Srb - Scsi Request block to free the scatter/gather list for.
Return Value:
None.
--*/
{
BOOLEAN succ;
BOOLEAN writeToDevice;
ULONG totalLength;
PSCATTER_GATHER_ELEMENT scatterList;
if (DeviceExtension->Mdl == NULL) {
return;
}
scatterList = DeviceExtension->ScatterGatherList.Elements;
totalLength = 0;
//
// Loop through the list, call IoFlushAdapterBuffers for each entry in
// the list.
//
writeToDevice = Srb->SrbFlags & SRB_FLAGS_DATA_OUT ? TRUE : FALSE;
while (totalLength < Srb->DataTransferLength) {
//
// Io is always done through the second map register.
//
succ = IoFlushAdapterBuffers(
DeviceExtension->DmaAdapterObject,
DeviceExtension->Mdl,
DeviceExtension->MapRegisterBase[1],
(PCCHAR)Srb->DataBuffer + totalLength,
scatterList->Length,
writeToDevice);
ASSERT (succ == TRUE);
totalLength += scatterList->Length;
scatterList++;
}
}
VOID
StartIo(
IN PSCSI_REQUEST_BLOCK Srb
)
/*++
Routine Description:
Arguments:
Srb - Request to start.
Return Value:
Nothing.
--*/
{
ULONG totalLength;
BOOLEAN writeToDevice;
//
// Set up SRB extension.
//
Srb->SrbExtension = DeviceExtension->SrbExtension;
//
// Flush the data buffer if necessary.
//
if (Srb->SrbFlags & (SRB_FLAGS_DATA_IN | SRB_FLAGS_DATA_OUT)) {
if (Srb->DataTransferLength > DeviceExtension->Capabilities.MaximumTransferLength) {
DebugPrint((1,
"StartIo: StartIo Length Exceeds limit (%x > %x)\n",
Srb->DataTransferLength,
DeviceExtension->Capabilities.MaximumTransferLength));
}
HalFlushIoBuffers(
DeviceExtension->Mdl,
(BOOLEAN) (Srb->SrbFlags & SRB_FLAGS_DATA_IN ? TRUE : FALSE),
TRUE);
//
// Determine if this adapter needs map registers.
//
if (DeviceExtension->MasterWithAdapter) {
AllocateScatterGatherList (DeviceExtension, Srb);
}
}
//
// Set request timeout value from Srb SCSI.
//
DeviceExtension->RequestTimeoutCounter = Srb->TimeOutValue;
//
// Send SRB to miniport driver. Miniport driver will notify when
// it completes.
//
if (DeviceExtension->PortType == StorPort &&
DeviceExtension->HwBuildIo != NULL) {
DeviceExtension->HwBuildIo (DeviceExtension->HwDeviceExtension, Srb);
}
DeviceExtension->HwStartIo(DeviceExtension->HwDeviceExtension, Srb);
}
VOID
TickHandler(
IN PSCSI_REQUEST_BLOCK Srb
)
/*++
Routine Description:
This routine simulates a 1-second tickhandler and is used to time
requests.
Arguments:
Srb - request being timed.
Return Value:
None.
--*/
{
if (DeviceExtension->RequestPending) {
//
// Check for busy requests.
//
if (DeviceExtension->Flags & PD_LOGICAL_UNIT_IS_BUSY) {
DebugPrint((1,"TickHandler: Retrying busy status request\n"));
//
// Clear the busy flag and retry the request.
//
DeviceExtension->Flags &= ~PD_LOGICAL_UNIT_IS_BUSY;
StartIo(Srb);
} else if (DeviceExtension->RequestTimeoutCounter == 0) {
ULONG i;
//
// Request timed out.
//
DebugPrint((1, "TickHandler: Request timed out\n"));
DebugPrint((1,
"TickHandler: CDB operation code %x\n",
DeviceExtension->Srb.Cdb[0]));
DebugPrint((1,
"TickHandler: Retry count %x\n",
DeviceExtension->RetryCount));
//
// Reset request timeout counter to unused state.
//
DeviceExtension->RequestTimeoutCounter = -1;
if (!ResetBus(DeviceExtension, 0)) {
DebugPrint((1,"Reset SCSI bus failed\n"));
}
//
// Call the interupt handler for a few microseconds to clear any reset
// interrupts.
//
for (i = 0; i < 1000 * 100; i++) {
DeviceExtension->StallRoutine(10);
if (DeviceExtension->HwInterrupt != NULL) {
DeviceExtension->HwInterrupt(DeviceExtension->HwDeviceExtension);
}
}
//
// Wait 2 seconds for the devices to recover after the reset.
//
DeviceExtension->StallRoutine(2 * SECONDS);
} else if (DeviceExtension->RequestTimeoutCounter != -1) {
DeviceExtension->RequestTimeoutCounter--;
}
}
}
VOID
ExecuteSrb(
IN PSCSI_REQUEST_BLOCK Srb
)
/*++
Routine Description:
This routine calls the start I/O routine an waits for the request to
complete. During the wait for complete the interrupt routine is called,
also the timer routines are called at the appropriate times. After the
request completes a check is made to determine if an request sense needs
to be issued.
Arguments:
Srb - Request to execute.
Return Value:
Nothing.
--*/
{
ULONG milliSecondTime;
ULONG secondTime;
ULONG completionDelay;
//
// Show request is pending.
//
DeviceExtension->RequestPending = TRUE;
//
// Start the request.
//
StartIo(Srb);
//
// The completion delay controls how long interrupts are serviced after
// a request has been completed. This allows interrupts which occur after
// a completion to be serviced.
//
completionDelay = COMPLETION_DELAY;
//
// Wait for the SRB to complete.
//
while (DeviceExtension->RequestPending) {
//
// Wait 1 second then call the scsi port timer routine.
//
for (secondTime = 0; secondTime < 1000/ 250; secondTime++) {
for (milliSecondTime = 0; milliSecondTime < (250 * 1000 / PD_INTERLOOP_STALL); milliSecondTime++) {
if (!(DeviceExtension->Flags & PD_DISABLE_INTERRUPTS)) {
//
// Call miniport driver's interrupt routine.
//
if (DeviceExtension->HwInterrupt != NULL) {
DeviceExtension->HwInterrupt(DeviceExtension->HwDeviceExtension);
}
}
//
// If the request is complete, call the interrupt routine
// a few more times to clean up any extra interrupts.
//
if (!DeviceExtension->RequestPending) {
if (completionDelay-- == 0) {
goto done;
}
}
if (DeviceExtension->Flags & PD_ENABLE_CALL_REQUEST) {
//
// Call the miniport requested routine.
//
DeviceExtension->Flags &= ~PD_ENABLE_CALL_REQUEST;
DeviceExtension->HwRequestInterrupt(DeviceExtension->HwDeviceExtension);
if (DeviceExtension->Flags & PD_DISABLE_CALL_REQUEST) {
DeviceExtension->Flags &= ~(PD_DISABLE_INTERRUPTS | PD_DISABLE_CALL_REQUEST);
DeviceExtension->HwRequestInterrupt(DeviceExtension->HwDeviceExtension);
}
}
if (DeviceExtension->Flags & PD_CALL_DMA_STARTED) {
DeviceExtension->Flags &= ~PD_CALL_DMA_STARTED;
//
// Notify the miniport driver that the DMA has been
// started.
//
if (DeviceExtension->HwDmaStarted) {
DeviceExtension->HwDmaStarted(
DeviceExtension->HwDeviceExtension
);
}
}
//
// This enforces the delay between calls to the interrupt routine.
//
DeviceExtension->StallRoutine(PD_INTERLOOP_STALL);
//
// Check the miniport timer.
//
if (DeviceExtension->TimerValue != 0) {
DeviceExtension->TimerValue--;
if (DeviceExtension->TimerValue == 0) {
//
// The timer timed out so called requested timer routine.
//
DeviceExtension->HwTimerRequest(DeviceExtension->HwDeviceExtension);
}
}
}
}
TickHandler(Srb);
DebugPrint((1,"ExecuteSrb: Waiting for SRB request to complete (~3 sec)\n"));
}
done:
if (Srb == &DeviceExtension->Srb &&
Srb->SrbStatus != SRB_STATUS_SUCCESS) {
//
// Determine if a REQUEST SENSE command needs to be done.
//
if ((Srb->ScsiStatus == SCSISTAT_CHECK_CONDITION) &&
!DeviceExtension->FinishingUp) {
//
// Call IssueRequestSense and it will complete the request after
// the REQUEST SENSE completes.
//
DebugPrint((1,
"ExecuteSrb: Issue request sense\n"));
IssueRequestSense();
}
}
}
NTSTATUS
DiskDumpWrite(
IN PLARGE_INTEGER DiskByteOffset,
IN PMDL Mdl
)
/*++
Routine Description:
This is the entry point for write requests to the diskdump driver.
Arguments:
DiskByteOffset - Byte offset relative to beginning of partition.
Mdl - Memory descriptor list that defines this request.
Return Value:
Status of write operation.
--*/
{
PSCSI_REQUEST_BLOCK srb = &DeviceExtension->Srb;
PCDB cdb = (PCDB)&srb->Cdb;
ULONG blockOffset;
ULONG blockCount;
ULONG retryCount = 0;
//
// ISSUE - 2000/02/29 - math:
//
// This is here until the StartVa is page aligned in the dump code
// (MmMapPhysicalMdl).
//
Mdl->StartVa = PAGE_ALIGN( Mdl->StartVa );
DebugPrint((2,
"Write memory at %x for %x bytes\n",
Mdl->StartVa,
Mdl->ByteCount));
writeRetry:
if (retryCount) {
//
// Remap the Mdl for dump data if IssueRequestSense() is called
// in ExecuteSrb() due to a write error.
//
MmMapMemoryDumpMdl(Mdl);
}
//
// Zero SRB.
//
RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
//
// Save MDL in device extension.
//
DeviceExtension->Mdl = Mdl;
//
// Initialize SRB.
//
srb->Length = sizeof(SCSI_REQUEST_BLOCK);
srb->PathId = DeviceExtension->PathId;
srb->TargetId = DeviceExtension->TargetId;
srb->Lun = DeviceExtension->Lun;
srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
srb->SrbFlags = SRB_FLAGS_DATA_OUT |
SRB_FLAGS_DISABLE_SYNCH_TRANSFER |
SRB_FLAGS_DISABLE_DISCONNECT |
SRB_FLAGS_DISABLE_AUTOSENSE;
srb->SrbStatus = srb->ScsiStatus = 0;
srb->NextSrb = 0;
srb->TimeOutValue = 10;
srb->CdbLength = 10;
srb->DataTransferLength = Mdl->ByteCount;
//
// See if adapter needs the memory mapped.
//
if (DeviceExtension->MapBuffers) {
srb->DataBuffer = Mdl->MappedSystemVa;
//
// ISSUE - 2000/02/29 - math: Work-around bad callers.
//
// MapBuffers indicates the adapter expects srb->DataBuffer to be a valid VA reference
// MmMapDumpMdl initializes MappedSystemVa to point to a pre-defined VA region
// Make sure StartVa points to the same page, some callers do not initialize all mdl fields
//
Mdl->StartVa = PAGE_ALIGN( Mdl->MappedSystemVa );
} else {
srb->DataBuffer = (PVOID)((PCHAR)Mdl->StartVa + Mdl->ByteOffset);
}
//
// Initialize CDB for write command.
//
cdb->CDB10.OperationCode = SCSIOP_WRITE;
//
// Convert disk byte offset to block offset.
//
blockOffset = (ULONG)((DeviceExtension->PartitionOffset.QuadPart +
(*DiskByteOffset).QuadPart) /
DeviceExtension->BytesPerSector);
//
// Fill in CDB block address.
//
cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&blockOffset)->Byte3;
cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&blockOffset)->Byte2;
cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&blockOffset)->Byte1;
cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&blockOffset)->Byte0;
blockCount = Mdl->ByteCount >> DeviceExtension->SectorShift;
cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&blockCount)->Byte1;
cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&blockCount)->Byte0;
//
// Send SRB to miniport driver.
//
ExecuteSrb(srb);
//
// Retry SRBs returned with failing status.
//
if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
DebugPrint((0,
"Write request failed with SRB status %x\n",
srb->SrbStatus));
//
// If retries not exhausted then retry request.
//
if (retryCount < 2) {
retryCount++;
goto writeRetry;
}
return STATUS_UNSUCCESSFUL;
} else {
return STATUS_SUCCESS;
}
}
VOID
DiskDumpFinish(
VOID
)
/*++
Routine Description:
This routine sends ops that finish up the write
Arguments:
None.
Return Value:
Status of write operation.
--*/
{
PSCSI_REQUEST_BLOCK srb = &DeviceExtension->Srb;
PCDB cdb = (PCDB)&srb->Cdb;
ULONG retryCount = 0;
//
// No data will be transfered with these two requests. So set up
// our extension so that we don't try to flush any buffers.
//
DeviceExtension->InterruptFlags &= ~PD_FLUSH_ADAPTER_BUFFERS;
DeviceExtension->InterruptFlags &= ~PD_MAP_TRANSFER;
DeviceExtension->MapRegisterBase[1] = 0;
DeviceExtension->FinishingUp = TRUE;
//
// Zero SRB.
//
RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
//
// Initialize SRB.
//
srb->Length = sizeof(SCSI_REQUEST_BLOCK);
srb->PathId = DeviceExtension->PathId;
srb->TargetId = DeviceExtension->TargetId;
srb->Lun = DeviceExtension->Lun;
srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
srb->SrbFlags = SRB_FLAGS_DISABLE_SYNCH_TRANSFER |
SRB_FLAGS_DISABLE_DISCONNECT |
SRB_FLAGS_DISABLE_AUTOSENSE;
srb->SrbStatus = srb->ScsiStatus = 0;
srb->NextSrb = 0;
srb->TimeOutValue = 10;
srb->CdbLength = 10;
//
// Initialize CDB for write command.
//
cdb->CDB10.OperationCode = SCSIOP_SYNCHRONIZE_CACHE;
//
// Send SRB to miniport driver.
//
ExecuteSrb(srb);
srb->CdbLength = 0;
srb->Function = SRB_FUNCTION_SHUTDOWN;
srb->SrbFlags = SRB_FLAGS_DISABLE_SYNCH_TRANSFER |
SRB_FLAGS_DISABLE_DISCONNECT |
SRB_FLAGS_DISABLE_AUTOSENSE;
srb->SrbStatus = srb->ScsiStatus = 0;
srb->NextSrb = 0;
srb->TimeOutValue = 0;
ExecuteSrb(srb);
}
ULONG
GetDeviceTransferSize(
PVOID PortConfig
)
{
ULONG TransferLength;
//
// For all other bus types ISA, EISA, MicroChannel set to the minimum
// known supported size (ex., 32kb)
//
TransferLength = MINIMUM_TRANSFER_SIZE;
//
// Return the maximum transfer size for the adapter.
//
if ( PortConfig ) {
PPORT_CONFIGURATION_INFORMATION ConfigInfo = PortConfig;
//
// Init the transfer length if it exists in port config
//
if ( ConfigInfo->MaximumTransferLength ) {
TransferLength = ConfigInfo->MaximumTransferLength;
}
//
// If the bus is PCI then increase the maximum transfer size
//
if ( ConfigInfo->AdapterInterfaceType == PCIBus) {
if ( TransferLength > MAXIMUM_TRANSFER_SIZE) {
TransferLength = MAXIMUM_TRANSFER_SIZE;
}
} else {
if (TransferLength > MINIMUM_TRANSFER_SIZE) {
TransferLength = MINIMUM_TRANSFER_SIZE;
}
}
}
return TransferLength;
}
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
/*++
Routine Description:
This is the system's entry point into the diskdump driver.
Arguments:
DriverObject - Not used.
RegistryPath - Using this field to pass initialization parameters.
Return Value:
STATUS_SUCCESS
--*/
{
PDUMP_INITIALIZATION_CONTEXT context = (PDUMP_INITIALIZATION_CONTEXT)RegistryPath;
PMEMORY_HEADER memoryHeader;
ULONG i;
PSCSI_ADDRESS TargetAddress;
//
// Zero the entire device extension and memory blocks.
//
RtlZeroMemory( context->MemoryBlock, 8*PAGE_SIZE );
RtlZeroMemory( context->CommonBuffer[0], context->CommonBufferSize );
RtlZeroMemory( context->CommonBuffer[1], context->CommonBufferSize );
//
// Allocate device extension from free memory block.
//
memoryHeader = (PMEMORY_HEADER)context->MemoryBlock;
DeviceExtension =
(PDEVICE_EXTENSION)((PUCHAR)memoryHeader + sizeof(MEMORY_HEADER));
//
// Initialize memory descriptor.
//
memoryHeader->Length = sizeof(DEVICE_EXTENSION) + sizeof(MEMORY_HEADER);
memoryHeader->Next = NULL;
//
// Fill in first free memory header.
//
DeviceExtension->FreeMemory =
(PMEMORY_HEADER)((PUCHAR)memoryHeader + memoryHeader->Length);
DeviceExtension->FreeMemory->Length =
(8*PAGE_SIZE) - memoryHeader->Length;
DeviceExtension->FreeMemory->Next = NULL;
//
// Store away init parameters.
//
DeviceExtension->StallRoutine = context->StallRoutine;
DeviceExtension->CommonBufferSize = context->CommonBufferSize;
TargetAddress = context->TargetAddress;
//
// Make sure that the common buffer size is backed by enough crash dump ptes
// The size is defined by MAXIMUM_TRANSFER_SIZE
//
if (DeviceExtension->CommonBufferSize > MAXIMUM_TRANSFER_SIZE) {
DeviceExtension->CommonBufferSize = MAXIMUM_TRANSFER_SIZE;
}
//
// Formerly, we allowed NULL TargetAddresses. No more. We must have
// a valid SCSI TargetAddress to create the dump. If not, just fail
// here.
//
if ( TargetAddress == NULL ) {
return STATUS_INVALID_PARAMETER;
}
DeviceExtension->PathId = TargetAddress->PathId;
DeviceExtension->TargetId = TargetAddress->TargetId;
DeviceExtension->Lun = TargetAddress->Lun;
DebugPrint((1,"DiskDump[DriverEntry] ScsiAddress.Length = %x\n",TargetAddress->Length));
DebugPrint((1,"DiskDump[DriverEntry] ScsiAddress.PortNumber = %x\n",TargetAddress->PortNumber));
DebugPrint((1,"DiskDump[DriverEntry] ScisAddress.PathId = %x\n",TargetAddress->PathId));
DebugPrint((1,"DiskDump[DriverEntry] ScisAddress.TargetId = %x\n",TargetAddress->TargetId));
DebugPrint((1,"DiskDump[DriverEntry] ScisAddress.Lun = %x\n",TargetAddress->Lun));
//
// Save off common buffer's virtual and physical addresses.
//
for (i = 0; i < 2; i++) {
DeviceExtension->CommonBuffer[i] = context->CommonBuffer[i];
//
// Convert the va of the buffer to obtain the PhysicalAddress
//
DeviceExtension->PhysicalAddress[i] =
MmGetPhysicalAddress(context->CommonBuffer[i]);
}
//
// Save driver parameters.
//
DeviceExtension->DmaAdapterObject = (PADAPTER_OBJECT)context->AdapterObject;
DeviceExtension->ConfigurationInformation =
context->PortConfiguration;
//
// We need to fixup this field of the port configuration information.
//
if (*Mm64BitPhysicalAddress) {
DeviceExtension->ConfigurationInformation->Dma64BitAddresses = SCSI_DMA64_SYSTEM_SUPPORTED;
}
DeviceExtension->MappedAddressList = NULL;
if (context->MappedRegisterBase) {
DeviceExtension->MappedAddressList =
*(PMAPPED_ADDRESS *) context->MappedRegisterBase;
}
//
// Initialize request tracking booleans.
//
DeviceExtension->RequestPending = FALSE;
DeviceExtension->RequestComplete = FALSE;
//
// Return major entry points.
//
context->OpenRoutine = DiskDumpOpen;
context->WriteRoutine = DiskDumpWrite;
context->FinishRoutine = DiskDumpFinish;
context->MaximumTransferSize = GetDeviceTransferSize(context->PortConfiguration);
return STATUS_SUCCESS;
}
NTSTATUS
InitializeConfiguration(
IN PHW_INITIALIZATION_DATA HwInitData,
OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
IN BOOLEAN InitialCall
)
/*++
Routine Description:
This routine initializes the port configuration information structure.
Any necessary information is extracted from the registery.
Arguments:
DeviceExtension - Supplies the device extension.
HwInitializationData - Supplies the initial miniport data.
ConfigInfo - Supplies the configuration information to be
initialized.
InitialCall - Indicates that this is first call to this function.
If InitialCall is FALSE, then the perivous configuration information
is used to determine the new information.
Return Value:
Returns a status indicating the success or fail of the initializaiton.
--*/
{
ULONG i;
//
// If this is the initial call then zero the information and set
// the structure to the uninitialized values.
//
if (InitialCall) {
RtlZeroMemory(ConfigInfo, sizeof(PORT_CONFIGURATION_INFORMATION));
ConfigInfo->Length = sizeof(PORT_CONFIGURATION_INFORMATION);
ConfigInfo->AdapterInterfaceType = HwInitData->AdapterInterfaceType;
ConfigInfo->InterruptMode = Latched;
ConfigInfo->MaximumTransferLength = 0xffffffff;
ConfigInfo->NumberOfPhysicalBreaks = 0xffffffff;
ConfigInfo->DmaChannel = 0xffffffff;
ConfigInfo->NumberOfAccessRanges = HwInitData->NumberOfAccessRanges;
ConfigInfo->MaximumNumberOfTargets = 8;
for (i = 0; i < 8; i++) {
ConfigInfo->InitiatorBusId[i] = ~0;
}
}
return STATUS_SUCCESS;
}
PINQUIRYDATA
IssueInquiry(
)
/*++
Routine Description:
This routine prepares an INQUIRY command that is sent to the miniport driver.
Arguments:
None.
Return Value:
Address of INQUIRY data.
--*/
{
PSCSI_REQUEST_BLOCK srb = &DeviceExtension->Srb;
PCDB cdb = (PCDB)&srb->Cdb;
ULONG retryCount = 0;
PINQUIRYDATA inquiryData = DeviceExtension->CommonBuffer[1];
PPFN_NUMBER page;
PFN_NUMBER localMdl[(sizeof( MDL )/sizeof(PFN_NUMBER)) + (MAXIMUM_TRANSFER_SIZE / PAGE_SIZE) + 2];
inquiryRetry:
//
// Zero SRB.
//
RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
//
// Initialize SRB.
//
srb->Length = sizeof(SCSI_REQUEST_BLOCK);
srb->PathId = DeviceExtension->PathId;
srb->TargetId = DeviceExtension->TargetId;
srb->Lun = DeviceExtension->Lun;
srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
srb->SrbFlags = SRB_FLAGS_DATA_IN |
SRB_FLAGS_DISABLE_SYNCH_TRANSFER |
SRB_FLAGS_DISABLE_DISCONNECT |
SRB_FLAGS_DISABLE_AUTOSENSE;
srb->SrbStatus = srb->ScsiStatus = 0;
srb->NextSrb = 0;
srb->TimeOutValue = 5;
srb->CdbLength = 6;
srb->DataBuffer = inquiryData;
srb->DataTransferLength = INQUIRYDATABUFFERSIZE;
//
// Build MDL and map it so that it can be used.
//
DeviceExtension->Mdl = (PMDL)&localMdl[0];
MmInitializeMdl(DeviceExtension->Mdl,
srb->DataBuffer,
srb->DataTransferLength);
page = MmGetMdlPfnArray ( DeviceExtension->Mdl );
*page = (PFN_NUMBER)(DeviceExtension->PhysicalAddress[1].QuadPart >> PAGE_SHIFT);
MmMapMemoryDumpMdl(DeviceExtension->Mdl);
//
// Initialize CDB for INQUIRY command.
//
cdb->CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY;
cdb->CDB6INQUIRY.LogicalUnitNumber = 0;
cdb->CDB6INQUIRY.Reserved1 = 0;
cdb->CDB6INQUIRY.AllocationLength = INQUIRYDATABUFFERSIZE;
cdb->CDB6INQUIRY.PageCode = 0;
cdb->CDB6INQUIRY.IReserved = 0;
cdb->CDB6INQUIRY.Control = 0;
//
// Send SRB to miniport driver.
//
ExecuteSrb(srb);
if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS &&
SRB_STATUS(srb->SrbStatus) != SRB_STATUS_DATA_OVERRUN) {
DebugPrint((2,
"IssueInquiry: Inquiry failed SRB status %x\n",
srb->SrbStatus));
if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SELECTION_TIMEOUT &&
retryCount < 2) {
//
// If the selection did not time out then retry the request.
//
retryCount++;
goto inquiryRetry;
} else {
return NULL;
}
}
return inquiryData;
}
VOID
IssueReadCapacity(
)
/*++
Routine Description:
This routine prepares a READ CAPACITY command that is sent to the
miniport driver.
Arguments:
None.
Return Value:
None.
--*/
{
PSCSI_REQUEST_BLOCK srb = &DeviceExtension->Srb;
PCDB cdb = (PCDB)&srb->Cdb;
PREAD_CAPACITY_DATA readCapacityData = DeviceExtension->CommonBuffer[1];
ULONG retryCount = 0;
PPFN_NUMBER page;
PFN_NUMBER localMdl[(sizeof( MDL )/sizeof(PFN_NUMBER)) + (MAXIMUM_TRANSFER_SIZE / PAGE_SIZE) + 2];
//
// Zero SRB.
//
RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
readCapacityRetry:
//
// Initialize SRB.
//
srb->Length = sizeof(SCSI_REQUEST_BLOCK);
srb->PathId = DeviceExtension->PathId;
srb->TargetId = DeviceExtension->TargetId;
srb->Lun = DeviceExtension->Lun;
srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
srb->SrbFlags = SRB_FLAGS_DATA_IN |
SRB_FLAGS_DISABLE_SYNCH_TRANSFER |
SRB_FLAGS_DISABLE_AUTOSENSE |
SRB_FLAGS_DISABLE_DISCONNECT;
srb->SrbStatus = srb->ScsiStatus = 0;
srb->NextSrb = 0;
srb->TimeOutValue = 5;
srb->CdbLength = 10;
srb->DataBuffer = readCapacityData;
srb->DataTransferLength = sizeof(READ_CAPACITY_DATA);
//
// Build MDL and map it so that it can be used.
//
DeviceExtension->Mdl = (PMDL) &localMdl[0];
MmInitializeMdl(DeviceExtension->Mdl,
srb->DataBuffer,
srb->DataTransferLength);
page = MmGetMdlPfnArray (DeviceExtension->Mdl);
*page = (PFN_NUMBER)(DeviceExtension->PhysicalAddress[1].QuadPart >> PAGE_SHIFT);
MmMapMemoryDumpMdl(DeviceExtension->Mdl);
//
// Initialize CDB.
//
cdb->CDB6GENERIC.OperationCode = SCSIOP_READ_CAPACITY;
//
// Send SRB to miniport driver.
//
ExecuteSrb(srb);
if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS &&
(SRB_STATUS(srb->SrbStatus) != SRB_STATUS_DATA_OVERRUN || srb->Cdb[0] == SCSIOP_READ_CAPACITY)) {
DebugPrint((1,
"ReadCapacity failed SRB status %x\n",
srb->SrbStatus));
if (retryCount < 2) {
//
// If the selection did not time out then retry the request.
//
retryCount++;
goto readCapacityRetry;
} else {
//
// Guess and hope that the block size is 512.
//
DeviceExtension->BytesPerSector = 512;
DeviceExtension->SectorShift = 9;
}
} else {
//
// Assuming that the 2 lsb is the only non-zero byte, this puts it in
// the right place.
//
DeviceExtension->BytesPerSector = readCapacityData->BytesPerBlock >> 8;
WHICH_BIT(DeviceExtension->BytesPerSector, DeviceExtension->SectorShift);
//
// Check for return size of zero. Set to default size and pass the problem downstream
//
if (!DeviceExtension->BytesPerSector) {
DeviceExtension->BytesPerSector = 512;
DeviceExtension->SectorShift = 9;
}
}
}
ULONG
ScsiPortInitialize(
IN PVOID Argument1,
IN PVOID Argument2,
IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
IN PVOID HwContext
)
/*++
Routine Description:
This routine is called by miniport driver to complete initialization.
Port configuration structure contains data from the miniport's previous
initialization and all system resources should be assigned and valid.
Arguments:
Argument1 - Not used.
Argument2 - Not used.
HwInitializationData - Miniport initialization structure
HwContext - Value passed to miniport driver's config routine
Return Value:
NT Status - STATUS_SUCCESS if boot device found.
--*/
{
BOOLEAN succ;
ULONG status;
ULONG srbStatus;
PPORT_CONFIGURATION_INFORMATION configInfo;
PIO_SCSI_CAPABILITIES capabilities;
ULONG length;
BOOLEAN callAgain;
UCHAR dumpString[] = "dump=1;";
UCHAR crashDump[32];
PINQUIRYDATA inquiryData;
BOOLEAN allocatedConfigInfo;
ASSERT ( DeviceExtension != NULL );
//
// Check if boot device has already been found.
//
if (DeviceExtension->FoundBootDevice) {
return (ULONG)STATUS_UNSUCCESSFUL;
}
//
// Initialization
//
DeviceExtension->HwDeviceExtension = NULL;
DeviceExtension->SpecificLuExtension = NULL;
configInfo = NULL;
capabilities = NULL;
inquiryData = NULL;
allocatedConfigInfo = FALSE;
RtlCopyMemory(crashDump,
dumpString,
strlen(dumpString) + 1);
//
// Check size of init data structure.
//
if (HwInitializationData->HwInitializationDataSize > sizeof(HW_INITIALIZATION_DATA)) {
return (ULONG) STATUS_REVISION_MISMATCH;
} else if (HwInitializationData->HwInitializationDataSize ==
FIELD_OFFSET (HW_INITIALIZATION_DATA, HwBuildIo)) {
DeviceExtension->PortType = ScsiPort;
} else {
DeviceExtension->PortType = StorPort;
}
//
// Check that each required entry is not NULL.
//
if ((!HwInitializationData->HwInitialize) ||
(!HwInitializationData->HwFindAdapter) ||
(!HwInitializationData->HwResetBus)) {
DebugPrint((0,
"ScsiPortInitialize: Miniport driver missing required entry\n"));
return (ULONG)STATUS_UNSUCCESSFUL;
}
//
// Set timer to -1 to indicate no outstanding request.
//
DeviceExtension->RequestTimeoutCounter = -1;
//
// Allocate memory for the miniport driver's device extension.
//
DeviceExtension->HwDeviceExtension =
AllocatePool(HwInitializationData->DeviceExtensionSize);
if (!DeviceExtension->HwDeviceExtension) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto done;
}
//
// Allocate memory for the hardware logical unit extension and
// zero it out.
//
if (HwInitializationData->SpecificLuExtensionSize) {
DeviceExtension->HwLogicalUnitExtensionSize =
HwInitializationData->SpecificLuExtensionSize;
DeviceExtension->SpecificLuExtension =
AllocatePool (HwInitializationData->SpecificLuExtensionSize);
if ( !DeviceExtension->SpecificLuExtension ) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto done;
}
RtlZeroMemory (
DeviceExtension->SpecificLuExtension,
DeviceExtension->HwLogicalUnitExtensionSize);
}
//
// Save the dependent driver routines in the device extension.
//
DeviceExtension->HwInitialize = HwInitializationData->HwInitialize;
DeviceExtension->HwStartIo = HwInitializationData->HwStartIo;
DeviceExtension->HwInterrupt = HwInitializationData->HwInterrupt;
DeviceExtension->HwReset = HwInitializationData->HwResetBus;
DeviceExtension->HwDmaStarted = HwInitializationData->HwDmaStarted;
DeviceExtension->HwLogicalUnitExtensionSize =
HwInitializationData->SpecificLuExtensionSize;
//
// If STORPORT grab the HwBuildIo routine.
//
if (DeviceExtension->PortType == StorPort) {
DeviceExtension->HwBuildIo = HwInitializationData->HwBuildIo;
} else {
DeviceExtension->HwBuildIo = NULL;
}
//
// Get pointer to capabilities structure.
//
capabilities = &DeviceExtension->Capabilities;
capabilities->Length = sizeof(IO_SCSI_CAPABILITIES);
//
// Check if port configuration information structure passed in from
// the system is valid.
//
if (configInfo = DeviceExtension->ConfigurationInformation) {
//
// Check to see if this structure applies to this miniport
// initialization. As long as they ask for more access ranges
// here than are required when they initialized with scsiport,
// we should be fine.
//
if((configInfo->AdapterInterfaceType != HwInitializationData->AdapterInterfaceType) ||
(HwInitializationData->NumberOfAccessRanges < configInfo->NumberOfAccessRanges)) {
//
// Don't initialize this time.
//
status = STATUS_NO_SUCH_DEVICE;
goto done;
}
} else {
//
// Allocate a new configuration information structure.
//
configInfo = AllocatePool(sizeof(PORT_CONFIGURATION_INFORMATION));
allocatedConfigInfo = TRUE;
if ( !configInfo ) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto done;
}
configInfo->AccessRanges = NULL;
//
// Set up configuration information structure.
//
status = InitializeConfiguration(
HwInitializationData,
configInfo,
TRUE);
if (!NT_SUCCESS (status)) {
status = STATUS_NO_SUCH_DEVICE;
goto done;
}
//
// Allocate memory for access ranges.
//
configInfo->NumberOfAccessRanges =
HwInitializationData->NumberOfAccessRanges;
configInfo->AccessRanges =
AllocatePool(sizeof(ACCESS_RANGE) * HwInitializationData->NumberOfAccessRanges);
if (configInfo->AccessRanges == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto done;
}
//
// Zero out access ranges.
//
RtlZeroMemory(configInfo->AccessRanges,
HwInitializationData->NumberOfAccessRanges
* sizeof(ACCESS_RANGE));
}
//
// Determine the maximum transfer size for this adapter
//
capabilities->MaximumTransferLength = GetDeviceTransferSize(configInfo);
DebugPrint ((1,
"DiskDump: Port Capabilities MaxiumTransferLength = 0x%08x\n",
capabilities->MaximumTransferLength));
//
// Get address of SRB extension.
//
DeviceExtension->SrbExtension = DeviceExtension->CommonBuffer[0];
DeviceExtension->SrbExtensionSize = HwInitializationData->SrbExtensionSize;
length = HwInitializationData->SrbExtensionSize;
length = (length + 7) & ~7;
//
// Get address of request sense buffer.
//
DeviceExtension->RequestSenseBuffer = (PSENSE_DATA)
((PUCHAR)DeviceExtension->CommonBuffer[0] + length);
length += sizeof(SENSE_DATA);
length = (length + 7) & ~7;
//
// Use the rest of the buffer for the noncached extension.
//
DeviceExtension->NonCachedExtension =
(PUCHAR)DeviceExtension->CommonBuffer[0] + length;
//
// Save the maximum size noncached extension can be.
//
DeviceExtension->NonCachedExtensionSize = DeviceExtension->CommonBufferSize - length;
//
// If a map registers are required, then allocate them permanently
// here using the adapter object passed in by the system.
//
if (DeviceExtension->DmaAdapterObject != NULL ) {
LARGE_INTEGER pfn;
PPFN_NUMBER page;
PMDL mdl;
ULONG numberOfPages;
ULONG i;
PFN_NUMBER localMdl[(sizeof( MDL )/sizeof (PFN_NUMBER)) + (MAXIMUM_TRANSFER_SIZE / PAGE_SIZE) + 2];
//
// Determine how many map registers are needed by considering
// the maximum transfer size and the size of the two common buffers.
//
numberOfPages = capabilities->MaximumTransferLength / PAGE_SIZE;
DeviceExtension->MapRegisterBase[0] =
HalAllocateCrashDumpRegisters(DeviceExtension->DmaAdapterObject,
&numberOfPages);
numberOfPages = capabilities->MaximumTransferLength / PAGE_SIZE;
DeviceExtension->MapRegisterBase[1] =
HalAllocateCrashDumpRegisters(DeviceExtension->DmaAdapterObject,
&numberOfPages);
//
// ISSUE - 2000/02/29 - math: Review.
//
// We assume this always succeeds for MAX TRANSFER SIZE as long
// as max transfer size is less than 64k
//
//
// Determine if adapter is a busmaster or uses slave DMA.
//
if (HwInitializationData->NeedPhysicalAddresses &&
configInfo->Master) {
DeviceExtension->MasterWithAdapter = TRUE;
} else {
DeviceExtension->MasterWithAdapter = FALSE;
}
//
// Build MDL to describe the first common buffer.
//
mdl = (PMDL)&localMdl[0];
MmInitializeMdl(mdl,
DeviceExtension->CommonBuffer[0],
DeviceExtension->CommonBufferSize);
//
// Get base of page index array at end of MDL.
//
page = MmGetMdlPfnArray (mdl);
//
// Calculate number of pages per memory block.
//
numberOfPages = DeviceExtension->CommonBufferSize / PAGE_SIZE;
//
// Fill in MDL description of first memory block.
//
for (i = 0; i < numberOfPages; i++) {
//
// Calculate first page.
//
*page = (PFN_NUMBER)((DeviceExtension->PhysicalAddress[0].QuadPart +
(PAGE_SIZE * i)) >> PAGE_SHIFT);
page++;
}
mdl->MdlFlags = MDL_PAGES_LOCKED;
//
// We need to Map the entire buffer.
//
length = DeviceExtension->CommonBufferSize;
//
// Convert physical buffer addresses to logical.
//
DeviceExtension->LogicalAddress[0] =
IoMapTransfer(
DeviceExtension->DmaAdapterObject,
mdl,
DeviceExtension->MapRegisterBase[0],
DeviceExtension->CommonBuffer[0],
&length,
FALSE);
//
// Build MDL to describe the second common buffer.
//
mdl = (PMDL)&localMdl[0];
MmInitializeMdl(mdl,
DeviceExtension->CommonBuffer[1],
DeviceExtension->CommonBufferSize);
//
// Get base of page index array at end of MDL.
//
page = MmGetMdlPfnArray ( mdl );
//
// Calculate number of pages per memory block.
//
numberOfPages = DeviceExtension->CommonBufferSize / PAGE_SIZE;
//
// Fill in MDL description of first memory block.
//
for (i = 0; i < numberOfPages; i++) {
//
// Calculate first page.
//
*page = (PFN_NUMBER)((DeviceExtension->PhysicalAddress[1].QuadPart +
(PAGE_SIZE * i)) >> PAGE_SHIFT);
page++;
}
//
// We need to map the entire buffer.
//
length = DeviceExtension->CommonBufferSize;
//
// Convert physical buffer addresses to logical.
//
DeviceExtension->LogicalAddress[1] =
IoMapTransfer(
DeviceExtension->DmaAdapterObject,
mdl,
DeviceExtension->MapRegisterBase[1],
DeviceExtension->CommonBuffer[1],
&length,
FALSE);
} else {
DeviceExtension->MasterWithAdapter = FALSE;
DeviceExtension->LogicalAddress[0] =
DeviceExtension->PhysicalAddress[0];
DeviceExtension->LogicalAddress[1] =
DeviceExtension->PhysicalAddress[1];
}
//
// Call miniport driver's find adapter routine.
//
if (HwInitializationData->HwFindAdapter(DeviceExtension->HwDeviceExtension,
HwContext,
NULL,
(PCHAR) crashDump,
configInfo,
&callAgain) != SP_RETURN_FOUND) {
status = STATUS_NO_SUCH_DEVICE;
goto done;
}
DebugPrint((1,
"SCSI adapter IRQ is %d\n",
configInfo->BusInterruptLevel));
DebugPrint((1,
"SCSI adapter ID is %d\n",
configInfo->InitiatorBusId[0]));
if (configInfo->NumberOfAccessRanges) {
DebugPrint((1,
"SCSI IO address is %x\n",
((*(configInfo->AccessRanges))[0]).RangeStart.LowPart));
}
//
// Set indicater as to whether adapter needs mapped buffers.
//
DeviceExtension->MapBuffers = configInfo->MapBuffers;
//
// Set maximum number of page breaks.
//
capabilities->MaximumPhysicalPages = configInfo->NumberOfPhysicalBreaks;
if (HwInitializationData->ReceiveEvent) {
capabilities->SupportedAsynchronousEvents |=
SRBEV_SCSI_ASYNC_NOTIFICATION;
}
capabilities->TaggedQueuing = HwInitializationData->TaggedQueuing;
capabilities->AdapterScansDown = configInfo->AdapterScansDown;
capabilities->AlignmentMask = configInfo->AlignmentMask;
//
// Make sure maximum nuber of pages is set to a reasonable value.
// This occurs for miniports with no Dma adapter.
//
if (capabilities->MaximumPhysicalPages == 0) {
capabilities->MaximumPhysicalPages =
(ULONG)ROUND_TO_PAGES(capabilities->MaximumTransferLength) + 1;
//
// Honor any limit requested by the miniport.
//
if (configInfo->NumberOfPhysicalBreaks < capabilities->MaximumPhysicalPages) {
capabilities->MaximumPhysicalPages =
configInfo->NumberOfPhysicalBreaks;
}
}
//
// Get maximum target IDs.
//
if (configInfo->MaximumNumberOfTargets > SCSI_MAXIMUM_TARGETS_PER_BUS) {
DeviceExtension->MaximumTargetIds = SCSI_MAXIMUM_TARGETS_PER_BUS;
} else {
DeviceExtension->MaximumTargetIds =
configInfo->MaximumNumberOfTargets;
}
//
// Get number of SCSI buses.
//
DeviceExtension->NumberOfBuses = configInfo->NumberOfBuses;
//
// Call the miniport driver to do its initialization.
//
if (!DeviceExtension->HwInitialize(DeviceExtension->HwDeviceExtension)) {
status = STATUS_INVALID_PARAMETER;
goto done;
}
//
// Issue the inquiry command.
//
inquiryData = IssueInquiry ();
if (inquiryData == NULL) {
status = STATUS_UNSUCCESSFUL;
goto done;
}
KdPrintEx ((
DPFLTR_CRASHDUMP_ID,
DPFLTR_TRACE_LEVEL,
"DISKDUMP: Inquiry: Type %d Qual %d Mod %d %s\n",
(LONG) inquiryData->DeviceType,
(LONG) inquiryData->DeviceTypeQualifier,
(LONG) inquiryData->DeviceTypeModifier,
inquiryData->RemovableMedia ? "Removable" : "Non-Removable"));
//
// Reset the bus.
//
succ = ResetBus (DeviceExtension, DeviceExtension->PathId);
if ( !succ ) {
status = STATUS_UNSUCCESSFUL;
goto done;
}
//
// Start the device.
//
srbStatus = StartDevice (
DeviceExtension->TargetId,
DeviceExtension->Lun);
if (srbStatus != SRB_STATUS_SUCCESS) {
//
// SCSIOP_START_STOP_DEVICE is allowed to fail. Some adapters (AMI MegaRAID)
// fail this request.
//
DebugPrint ((0, "DISKDUMP: PathId=%x TargetId=%x Lun=%x failed to start srbStatus = %d\n",
DeviceExtension->PathId, DeviceExtension->TargetId,
DeviceExtension->Lun, (LONG) srbStatus));
}
//
// Initialize the driver's capacity data (BytesPerSector, etc.)
//
IssueReadCapacity ();
//
// NOTE: We may want to go a sanity check that we have actually found
// the correct drive. On MBR disks this can be accomplished by looking
// at the NTFT disk signature. On GPT disks we can look at the DiskId.
// This only makes a difference if the crashdump code gave us the
// wrong TargetId, Lun, which it should never do.
//
DeviceExtension->FoundBootDevice = TRUE;
status = STATUS_SUCCESS;
done:
//
// On failure, free all resources.
//
if ( !NT_SUCCESS (status) ) {
//
// The config info can either come from space we allocated or from
// the DUMP_INITIALIZATION_CONTEXT. If it was allocated and we failed
// we need to free it.
//
if (allocatedConfigInfo && configInfo != NULL) {
if (configInfo->AccessRanges != NULL) {
FreePool (configInfo->AccessRanges);
configInfo->AccessRanges = NULL;
}
FreePool (configInfo);
configInfo = NULL;
}
if (DeviceExtension->HwDeviceExtension) {
FreePool (DeviceExtension->HwDeviceExtension);
DeviceExtension->HwDeviceExtension = NULL;
}
if (DeviceExtension->SpecificLuExtension) {
FreePool (DeviceExtension->SpecificLuExtension);
DeviceExtension->SpecificLuExtension = NULL;
}
}
return (ULONG) status;
}
//
// Routines providing service to hardware dependent driver.
//
SCSI_PHYSICAL_ADDRESS
ScsiPortGetPhysicalAddress(
IN PVOID HwDeviceExtension,
IN PSCSI_REQUEST_BLOCK Srb,
IN PVOID VirtualAddress,
OUT ULONG *Length
)
/*++
Routine Description:
This routine returns a 32-bit physical address to which a virtual address
is mapped. There are 2 types addresses that can be translated via this call:
- An address of memory from the two common buffers that the system provides
for the crashdump disk drivers.
- A data buffer address described in an MDL that the system provided with
an IO request.
Arguments:
Return Value:
--*/
{
PSCATTER_GATHER_ELEMENT scatterList;
PMDL mdl;
ULONG byteOffset;
ULONG whichPage;
PPFN_NUMBER pages;
PHYSICAL_ADDRESS address;
//
// There are two distinct types of memory addresses for which a
// physical address must be calculated.
//
// The first is the data buffer passed in an SRB.
//
// The second is an address within the common buffer which is
// the noncached extension or SRB extensions.
//
if (Srb) {
//
// There are two distinct types of adapters that require physical
// addresses.
//
// The first is busmaster devices for which scatter/gather lists
// have already been built.
//
// The second is slave or system DMA devices. As the diskdump driver
// will program the system DMA hardware, the miniport driver will never
// need to see the physical addresses, so I don't think it will ever
// make this call.
//
if (DeviceExtension->MasterWithAdapter) {
//
// A scatter/gather list has already been allocated. Use it to determine
// the physical address and length. Get the scatter/gather list.
//
scatterList = DeviceExtension->ScatterGatherList.Elements;
//
// Calculate byte offset into the data buffer.
//
byteOffset = (ULONG)((PCHAR)VirtualAddress - (PCHAR)Srb->DataBuffer);
//
// Find the appropriate entry in the scatter/gatter list.
//
while (byteOffset >= scatterList->Length) {
byteOffset -= scatterList->Length;
scatterList++;
}
//
// Calculate the physical address and length to be returned.
//
*Length = scatterList->Length - byteOffset;
address.QuadPart = scatterList->Address.QuadPart + byteOffset;
} else {
DebugPrint((0,
"DISKDUMP: Jeff led me to believe this code may never get executed.\n"));
//
// Get MDL.
//
mdl = DeviceExtension->Mdl;
//
// Calculate byte offset from
// beginning of first physical page.
//
if (DeviceExtension->MapBuffers) {
byteOffset = (ULONG)((PCHAR)VirtualAddress - (PCHAR)mdl->MappedSystemVa);
} else {
byteOffset = (ULONG)((PCHAR)VirtualAddress - (PCHAR)mdl->StartVa);
}
//
// Calculate which physical page.
//
whichPage = byteOffset >> PAGE_SHIFT;
//
// Calculate beginning of physical page array.
//
pages = MmGetMdlPfnArray ( mdl );
//
// Calculate physical address.
//
address.QuadPart = (pages[whichPage] << PAGE_SHIFT) +
BYTE_OFFSET(VirtualAddress);
}
} else {
//
// Miniport SRB extensions and noncached extensions come from
// common buffer 0.
//
if (VirtualAddress >= DeviceExtension->CommonBuffer[0] &&
VirtualAddress <
(PVOID)((PUCHAR)DeviceExtension->CommonBuffer[0] + DeviceExtension->CommonBufferSize)) {
address.QuadPart =
(ULONG_PTR)((PUCHAR)VirtualAddress -
(PUCHAR)DeviceExtension->CommonBuffer[0]) +
DeviceExtension->LogicalAddress[0].QuadPart;
*Length = (ULONG)(DeviceExtension->CommonBufferSize -
((PUCHAR)VirtualAddress -
(PUCHAR)DeviceExtension->CommonBuffer[0]));
} else if (VirtualAddress >= DeviceExtension->CommonBuffer[1] &&
VirtualAddress <
(PVOID)((PUCHAR)DeviceExtension->CommonBuffer[1] + DeviceExtension->CommonBufferSize)) {
address.QuadPart =
(ULONG_PTR)((PUCHAR)VirtualAddress -
(PUCHAR)DeviceExtension->CommonBuffer[1]) +
DeviceExtension->LogicalAddress[1].QuadPart;
*Length = (ULONG)(DeviceExtension->CommonBufferSize -
((PUCHAR)VirtualAddress -
(PUCHAR)DeviceExtension->CommonBuffer[1]));
} else {
DbgPrint("Crashdump: miniport attempted to get physical address "
"for invalid VA %#p\n", VirtualAddress);
DbgPrint("Crashdump: Valid range 1: %p through %p\n",
(PUCHAR) DeviceExtension->CommonBuffer[0],
((PUCHAR) DeviceExtension->CommonBuffer[0]) + DeviceExtension->CommonBufferSize);
DbgPrint("Crashdump: Valid ranges 2: %p through %p\n",
(PUCHAR) DeviceExtension->CommonBuffer[1],
((PUCHAR) DeviceExtension->CommonBuffer[1]) + DeviceExtension->CommonBufferSize);
KeBugCheckEx(PORT_DRIVER_INTERNAL,
0x80000001,
(ULONG_PTR) DeviceExtension,
(ULONG_PTR) VirtualAddress,
(ULONG_PTR) NULL);
address.QuadPart = 0;
*Length = 0;
}
}
return address;
}
#define CHECK_POINTER_RANGE(LowerBound,Address,Size)\
((PUCHAR)(LowerBound) <= (PUCHAR)(Address) && \
(PUCHAR)Address < ((PUCHAR)(LowerBound) + Size))
SCSI_PHYSICAL_ADDRESS
StorPortGetPhysicalAddress(
IN PVOID HwDeviceExtension,
IN PSCSI_REQUEST_BLOCK Srb,
IN PVOID VirtualAddress,
OUT ULONG *Length
)
/*++
Routine Description:
This routine returns a 32-bit physical address to which a virtual address
is mapped. There are 2 types addresses that can be translated via this call:
- An address of memory from the two common buffers that the system provides
for the crashdump disk drivers.
- A data buffer address described in an MDL that the system provided with
an IO request.
Arguments:
Return Value:
--*/
{
//
// Unlike SCSIPORT, STORPORT requires a SRB for the SRB's DataBuffer,
// SenseInfoBuffer and SrbExtension. If this is one of these cases,
// translate it back to the SCSIPORT usage.
//
if (Srb &&
CHECK_POINTER_RANGE (Srb->SrbExtension, VirtualAddress,
DeviceExtension->SrbExtensionSize)) {
Srb = NULL;
}
return ScsiPortGetPhysicalAddress (HwDeviceExtension,
Srb,
VirtualAddress,
Length);
}
PVOID
ScsiPortGetVirtualAddress(
IN PVOID HwDeviceExtension,
IN SCSI_PHYSICAL_ADDRESS PhysicalAddress
)
/*++
Routine Description:
This routine is returns a virtual address associated with a
physical address, if the physical address was obtained by a
call to ScsiPortGetPhysicalAddress.
Arguments:
PhysicalAddress
Return Value:
Virtual address if physical page hashed.
NULL if physical page not found in hash.
--*/
{
ULONG address = ScsiPortConvertPhysicalAddressToUlong(PhysicalAddress);
ULONG offset;
//
// Check if address is in the range of the first common buffer.
//
if (address >= DeviceExtension->PhysicalAddress[0].LowPart &&
address < (DeviceExtension->PhysicalAddress[0].LowPart +
DeviceExtension->CommonBufferSize)) {
offset = address - DeviceExtension->PhysicalAddress[0].LowPart;
return ((PUCHAR)DeviceExtension->CommonBuffer[0] + offset);
}
//
// Check if the address is in the range of the second common buffer.
//
if (address >= DeviceExtension->PhysicalAddress[1].LowPart &&
address < (DeviceExtension->PhysicalAddress[1].LowPart +
DeviceExtension->CommonBufferSize)) {
offset = address - DeviceExtension->PhysicalAddress[1].LowPart;
return ((PUCHAR)DeviceExtension->CommonBuffer[1] + offset);
}
return NULL;
}
PVOID
ScsiPortGetLogicalUnit(
IN PVOID HwDeviceExtension,
IN UCHAR PathId,
IN UCHAR TargetId,
IN UCHAR Lun
)
/*++
Routine Description:
Return miniport driver's logical unit extension.
Arguments:
HwDeviceExtension - The port driver's device extension follows
the miniport's device extension and contains a pointer to
the logical device extension list.
PathId, TargetId and Lun - identify which logical unit on the
SCSI buses.
Return Value:
Miniport driver's logical unit extension
--*/
{
return DeviceExtension->SpecificLuExtension;
}
VOID
ScsiPortNotification(
IN SCSI_NOTIFICATION_TYPE NotificationType,
IN PVOID HwDeviceExtension,
...
)
{
PSCSI_REQUEST_BLOCK srb = NULL;
va_list(ap);
va_start(ap, HwDeviceExtension);
switch (NotificationType) {
case NextLuRequest:
case NextRequest:
//
// Start next packet on adapter's queue.
//
DeviceExtension->InterruptFlags |= PD_READY_FOR_NEXT_REQUEST;
break;
case RequestComplete:
//
// Record completed request.
//
srb = va_arg(ap, PSCSI_REQUEST_BLOCK);
//
// Check which SRB is completing.
//
if (srb == &DeviceExtension->Srb) {
//
// Complete this request.
//
DeviceExtension->RequestComplete = TRUE;
} else if (srb == &DeviceExtension->RequestSenseSrb) {
//
// Process request sense.
//
RequestSenseCompletion();
}
break;
case ResetDetected:
//
// Delay for 4 seconds.
//
DeviceExtension->StallRoutine ( RESET_DELAY );
break;
case CallDisableInterrupts:
ASSERT(DeviceExtension->Flags & PD_DISABLE_INTERRUPTS);
//
// The miniport wants us to call the specified routine
// with interrupts disabled. This is done after the current
// HwRequestInterrutp routine completes. Indicate the call is
// needed and save the routine to be called.
//
DeviceExtension->Flags |= PD_DISABLE_CALL_REQUEST;
DeviceExtension->HwRequestInterrupt = va_arg(ap, PHW_INTERRUPT);
break;
case CallEnableInterrupts:
ASSERT(!(DeviceExtension->Flags & PD_DISABLE_INTERRUPTS));
//
// The miniport wants us to call the specified routine
// with interrupts enabled this is done from the DPC.
// Disable calls to the interrupt routine, indicate the call is
// needed and save the routine to be called.
//
DeviceExtension->Flags |= PD_DISABLE_INTERRUPTS | PD_ENABLE_CALL_REQUEST;
DeviceExtension->HwRequestInterrupt = va_arg(ap, PHW_INTERRUPT);
break;
case RequestTimerCall:
DeviceExtension->HwTimerRequest = va_arg(ap, PHW_INTERRUPT);
DeviceExtension->TimerValue = va_arg(ap, ULONG);
if (DeviceExtension->TimerValue) {
//
// Round up the timer value to the stall time.
//
DeviceExtension->TimerValue = (DeviceExtension->TimerValue
+ PD_INTERLOOP_STALL - 1)/ PD_INTERLOOP_STALL;
}
break;
}
va_end(ap);
//
// Check to see if the last DPC has been processed yet. If so
// queue another DPC.
//
WorkHorseDpc();
}
VOID
ScsiPortFlushDma(
IN PVOID HwDeviceExtension
)
/*++
Routine Description:
This routine checks to see if the previous IoMapTransfer has been done
started. If it has not, then the PD_MAP_TRANSER flag is cleared, and the
routine returns; otherwise, this routine schedules a DPC which will call
IoFlushAdapter buffers.
Arguments:
HwDeviceExtension - Supplies a the hardware device extension for the
host bus adapter which will be doing the data transfer.
Return Value:
None.
--*/
{
if (DeviceExtension->InterruptFlags & PD_MAP_TRANSFER) {
//
// The transfer has not been started so just clear the map transfer
// flag and return.
//
DeviceExtension->InterruptFlags &= ~PD_MAP_TRANSFER;
return;
}
DeviceExtension->InterruptFlags |= PD_FLUSH_ADAPTER_BUFFERS;
//
// Check to see if the last DPC has been processed yet. If so
// queue another DPC.
//
WorkHorseDpc();
return;
}
VOID
ScsiPortIoMapTransfer(
IN PVOID HwDeviceExtension,
IN PSCSI_REQUEST_BLOCK Srb,
IN PVOID LogicalAddress,
IN ULONG Length
)
/*++
Routine Description:
Saves the parameters for the call to IoMapTransfer and schedules the DPC
if necessary.
Arguments:
HwDeviceExtension - Supplies a the hardware device extension for the
host bus adapter which will be doing the data transfer.
Srb - Supplies the particular request that data transfer is for.
LogicalAddress - Supplies the logical address where the transfer should
begin.
Length - Supplies the maximum length in bytes of the transfer.
Return Value:
None.
--*/
{
//
// Make sure this host bus adapter has an Dma adapter object.
//
if (DeviceExtension->DmaAdapterObject == NULL) {
//
// No DMA adapter, no work.
//
return;
}
DeviceExtension->MapTransferParameters.Srb = Srb;
DeviceExtension->MapTransferParameters.LogicalAddress = LogicalAddress;
DeviceExtension->MapTransferParameters.Length = Length;
DeviceExtension->InterruptFlags |= PD_MAP_TRANSFER;
//
// Check to see if the last DPC has been processed yet. If so
// queue another DPC.
//
WorkHorseDpc();
}
VOID
ScsiPortLogError(
IN PVOID HwDeviceExtension,
IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
IN UCHAR PathId,
IN UCHAR TargetId,
IN UCHAR Lun,
IN ULONG ErrorCode,
IN ULONG UniqueId
)
/*++
Routine Description:
This routine does no more than put up a debug print message in a debug
build.
Arguments:
DeviceExtenson - Supplies the HBA miniport driver's adapter data storage.
TargetId, Lun and PathId - specify device address on a SCSI bus.
ErrorCode - Supplies an error code indicating the type of error.
UniqueId - Supplies a unique identifier for the error.
Return Value:
None.
--*/
{
DebugPrint((0,"\n\nLogErrorEntry: Logging SCSI error packet. ErrorCode = %d.\n",
ErrorCode));
DebugPrint((0,
"PathId = %2x, TargetId = %2x, Lun = %2x, UniqueId = %x.\n\n",
PathId,
TargetId,
Lun,
UniqueId));
return;
}
VOID
ScsiPortCompleteRequest(
IN PVOID HwDeviceExtension,
IN UCHAR PathId,
IN UCHAR TargetId,
IN UCHAR Lun,
IN UCHAR SrbStatus
)
/*++
Routine Description:
Complete all active requests for the specified logical unit.
Arguments:
DeviceExtenson - Supplies the HBA miniport driver's adapter data storage.
TargetId, Lun and PathId - specify device address on a SCSI bus.
SrbStatus - Status to be returned in each completed SRB.
Return Value:
None.
--*/
{
PSCSI_REQUEST_BLOCK srb = &DeviceExtension->Srb;
PSCSI_REQUEST_BLOCK failingSrb;
//
// Check if a request is outstanding.
//
if (!DeviceExtension->Mdl) {
return;
}
//
// Just in case this is an abort request,
// get pointer to failingSrb.
//
failingSrb = srb->NextSrb;
//
// Update SRB status and show no bytes transferred.
//
srb->SrbStatus = SrbStatus;
srb->DataTransferLength = 0;
//
// Call notification routine.
//
ScsiPortNotification(RequestComplete,
HwDeviceExtension,
srb);
//
// Check if this was an ABORT SRB
//
if (failingSrb) {
//
// This was an abort request. The failing
// SRB must also be completed.
//
failingSrb->SrbStatus = SrbStatus;
failingSrb->DataTransferLength = 0;
//
// Call notification routine.
//
ScsiPortNotification(RequestComplete,
HwDeviceExtension,
failingSrb);
}
return;
}
VOID
ScsiPortMoveMemory(
IN PVOID WriteBuffer,
IN PVOID ReadBuffer,
IN ULONG Length
)
/*++
Routine Description:
Copy from one buffer into another.
Arguments:
ReadBuffer - source
WriteBuffer - destination
Length - number of bytes to copy
Return Value:
None.
--*/
{
RtlMoveMemory(WriteBuffer, ReadBuffer, Length);
}
VOID
ScsiPortStallExecution(
ULONG Delay
)
/*++
Routine Description:
Wait number of microseconds in tight processor loop.
Arguments:
Delay - number of microseconds to wait.
Return Value:
None.
--*/
{
DeviceExtension->StallRoutine(Delay);
}
VOID
ScsiDebugPrint(
ULONG DebugPrintLevel,
PCCHAR DebugMessage,
...
)
/*++
Routine Description:
Debug print for all SCSI drivers
Arguments:
Debug print level between 0 and 3, with 3 being the most verbose.
Return Value:
None
--*/
{
#if DBG
va_list ap;
ULONG DebugLevel;
va_start( ap, DebugMessage );
switch (DebugPrintLevel) {
case 0:
DebugLevel = DPFLTR_WARNING_LEVEL;
break;
case 1:
case 2:
DebugLevel = DPFLTR_TRACE_LEVEL;
break;
case 3:
DebugLevel = DPFLTR_INFO_LEVEL;
break;
default:
DebugLevel = DebugPrintLevel;
break;
}
vDbgPrintExWithPrefix ("DISKDUMP: ",
DPFLTR_CRASHDUMP_ID,
DebugLevel,
DebugMessage,
ap);
va_end(ap);
#endif
}
UCHAR
ScsiPortReadPortUchar(
IN PUCHAR Port
)
/*++
Routine Description:
Read from the specificed port address.
Arguments:
Port - Supplies a pointer to the port address.
Return Value:
Returns the value read from the specified port address.
--*/
{
return(READ_PORT_UCHAR(Port));
}
USHORT
ScsiPortReadPortUshort(
IN PUSHORT Port
)
/*++
Routine Description:
Read from the specificed port address.
Arguments:
Port - Supplies a pointer to the port address.
Return Value:
Returns the value read from the specified port address.
--*/
{
return(READ_PORT_USHORT(Port));
}
ULONG
ScsiPortReadPortUlong(
IN PULONG Port
)
/*++
Routine Description:
Read from the specificed port address.
Arguments:
Port - Supplies a pointer to the port address.
Return Value:
Returns the value read from the specified port address.
--*/
{
return(READ_PORT_ULONG(Port));
}
UCHAR
ScsiPortReadRegisterUchar(
IN PUCHAR Register
)
/*++
Routine Description:
Read from the specificed register address.
Arguments:
Register - Supplies a pointer to the register address.
Return Value:
Returns the value read from the specified register address.
--*/
{
return(READ_REGISTER_UCHAR(Register));
}
USHORT
ScsiPortReadRegisterUshort(
IN PUSHORT Register
)
/*++
Routine Description:
Read from the specificed register address.
Arguments:
Register - Supplies a pointer to the register address.
Return Value:
Returns the value read from the specified register address.
--*/
{
return(READ_REGISTER_USHORT(Register));
}
ULONG
ScsiPortReadRegisterUlong(
IN PULONG Register
)
/*++
Routine Description:
Read from the specificed register address.
Arguments:
Register - Supplies a pointer to the register address.
Return Value:
Returns the value read from the specified register address.
--*/
{
return(READ_REGISTER_ULONG(Register));
}
VOID
ScsiPortReadRegisterBufferUchar(
IN PUCHAR Register,
IN PUCHAR Buffer,
IN ULONG Count
)
/*++
Routine Description:
Read a buffer of unsigned bytes from the specified register address.
Arguments:
Register - Supplies a pointer to the port address.
Buffer - Supplies a pointer to the data buffer area.
Count - The count of items to move.
Return Value:
None
--*/
{
READ_REGISTER_BUFFER_UCHAR(Register, Buffer, Count);
}
VOID
ScsiPortReadRegisterBufferUshort(
IN PUSHORT Register,
IN PUSHORT Buffer,
IN ULONG Count
)
/*++
Routine Description:
Read a buffer of unsigned shorts from the specified register address.
Arguments:
Register - Supplies a pointer to the port address.
Buffer - Supplies a pointer to the data buffer area.
Count - The count of items to move.
Return Value:
None
--*/
{
READ_REGISTER_BUFFER_USHORT(Register, Buffer, Count);
}
VOID
ScsiPortReadRegisterBufferUlong(
IN PULONG Register,
IN PULONG Buffer,
IN ULONG Count
)
/*++
Routine Description:
Read a buffer of unsigned longs from the specified register address.
Arguments:
Register - Supplies a pointer to the port address.
Buffer - Supplies a pointer to the data buffer area.
Count - The count of items to move.
Return Value:
None
--*/
{
READ_REGISTER_BUFFER_ULONG(Register, Buffer, Count);
}
VOID
ScsiPortWritePortUchar(
IN PUCHAR Port,
IN UCHAR Value
)
/*++
Routine Description:
Write to the specificed port address.
Arguments:
Port - Supplies a pointer to the port address.
Value - Supplies the value to be written.
Return Value:
None
--*/
{
WRITE_PORT_UCHAR(Port, Value);
}
VOID
ScsiPortWritePortUshort(
IN PUSHORT Port,
IN USHORT Value
)
/*++
Routine Description:
Write to the specificed port address.
Arguments:
Port - Supplies a pointer to the port address.
Value - Supplies the value to be written.
Return Value:
None
--*/
{
WRITE_PORT_USHORT(Port, Value);
}
VOID
ScsiPortWritePortUlong(
IN PULONG Port,
IN ULONG Value
)
/*++
Routine Description:
Write to the specificed port address.
Arguments:
Port - Supplies a pointer to the port address.
Value - Supplies the value to be written.
Return Value:
None
--*/
{
WRITE_PORT_ULONG(Port, Value);
}
VOID
ScsiPortWriteRegisterUchar(
IN PUCHAR Register,
IN UCHAR Value
)
/*++
Routine Description:
Write to the specificed register address.
Arguments:
Register - Supplies a pointer to the register address.
Value - Supplies the value to be written.
Return Value:
None
--*/
{
WRITE_REGISTER_UCHAR(Register, Value);
}
VOID
ScsiPortWriteRegisterUshort(
IN PUSHORT Register,
IN USHORT Value
)
/*++
Routine Description:
Write to the specificed register address.
Arguments:
Register - Supplies a pointer to the register address.
Value - Supplies the value to be written.
Return Value:
None
--*/
{
WRITE_REGISTER_USHORT(Register, Value);
}
VOID
ScsiPortWriteRegisterUlong(
IN PULONG Register,
IN ULONG Value
)
/*++
Routine Description:
Write to the specificed register address.
Arguments:
Register - Supplies a pointer to the register address.
Value - Supplies the value to be written.
Return Value:
None
--*/
{
WRITE_REGISTER_ULONG(Register, Value);
}
VOID
ScsiPortWriteRegisterBufferUchar(
IN PUCHAR Register,
IN PUCHAR Buffer,
IN ULONG Count
)
/*++
Routine Description:
Write a buffer of unsigned bytes from the specified register address.
Arguments:
Register - Supplies a pointer to the port address.
Buffer - Supplies a pointer to the data buffer area.
Count - The count of items to move.
Return Value:
None
--*/
{
WRITE_REGISTER_BUFFER_UCHAR(Register, Buffer, Count);
}
VOID
ScsiPortWriteRegisterBufferUshort(
IN PUSHORT Register,
IN PUSHORT Buffer,
IN ULONG Count
)
/*++
Routine Description:
Write a buffer of unsigned shorts from the specified register address.
Arguments:
Register - Supplies a pointer to the port address.
Buffer - Supplies a pointer to the data buffer area.
Count - The count of items to move.
Return Value:
None
--*/
{
WRITE_REGISTER_BUFFER_USHORT(Register, Buffer, Count);
}
VOID
ScsiPortWriteRegisterBufferUlong(
IN PULONG Register,
IN PULONG Buffer,
IN ULONG Count
)
/*++
Routine Description:
Write a buffer of unsigned longs from the specified register address.
Arguments:
Register - Supplies a pointer to the port address.
Buffer - Supplies a pointer to the data buffer area.
Count - The count of items to move.
Return Value:
None
--*/
{
WRITE_REGISTER_BUFFER_ULONG(Register, Buffer, Count);
}
SCSI_PHYSICAL_ADDRESS
ScsiPortConvertUlongToPhysicalAddress(
ULONG_PTR UlongAddress
)
{
SCSI_PHYSICAL_ADDRESS physicalAddress;
physicalAddress.QuadPart = UlongAddress;
return(physicalAddress);
}
ULONG
ScsiPortConvertPhysicalAddressToUlong(
PHYSICAL_ADDRESS Address
)
{
return(Address.LowPart);
}
PVOID
ScsiPortGetDeviceBase(
IN PVOID HwDeviceExtension,
IN INTERFACE_TYPE BusType,
IN ULONG SystemIoBusNumber,
SCSI_PHYSICAL_ADDRESS IoAddress,
ULONG NumberOfBytes,
BOOLEAN InIoSpace
)
/*++
Routine Description:
This routine maps an IO address to system address space.
This was done during system initialization for the crash dump driver.
Arguments:
HwDeviceExtension - used to find port device extension.
BusType - what type of bus - eisa, mca, isa
SystemIoBusNumber - which IO bus (for machines with multiple buses).
IoAddress - base device address to be mapped.
NumberOfBytes - number of bytes for which address is valid.
InIoSpace - indicates an IO address.
Return Value:
Mapped address
--*/
{
PMAPPED_ADDRESS Addresses = DeviceExtension->MappedAddressList;
PHYSICAL_ADDRESS CardAddress;
ULONG AddressSpace = InIoSpace;
PVOID MappedAddress = NULL;
BOOLEAN b;
b = HalTranslateBusAddress(
BusType, // AdapterInterfaceType
SystemIoBusNumber, // SystemIoBusNumber
IoAddress, // Bus Address
&AddressSpace, // AddressSpace
&CardAddress
);
if ( !b ) {
return NULL;
}
//
// If the address space is not in I/O space, then it was mapped during
// the original system initialization of the driver. Therefore, it must
// be in the list of mapped address ranges. Look it up and return it.
//
if (!AddressSpace) {
while (Addresses) {
if (SystemIoBusNumber == Addresses->BusNumber &&
NumberOfBytes == Addresses->NumberOfBytes &&
IoAddress.QuadPart == Addresses->IoAddress.QuadPart) {
MappedAddress = Addresses->MappedAddress;
break;
}
Addresses = Addresses->NextMappedAddress;
}
} else {
MappedAddress = (PVOID)(ULONG_PTR)CardAddress.QuadPart;
}
return MappedAddress;
}
VOID
ScsiPortFreeDeviceBase(
IN PVOID HwDeviceExtension,
IN PVOID MappedAddress
)
/*++
Routine Description:
This routine unmaps an IO address that has been previously mapped
to system address space using ScsiPortGetDeviceBase().
Arguments:
HwDeviceExtension - used to find port device extension.
MappedAddress - address to unmap.
NumberOfBytes - number of bytes mapped.
InIoSpace - addresses in IO space don't get mapped.
Return Value:
None
--*/
{
UNREFERENCED_PARAMETER(HwDeviceExtension);
UNREFERENCED_PARAMETER(MappedAddress);
return;
}
PVOID
ScsiPortGetUncachedExtension(
IN PVOID HwDeviceExtension,
IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
IN ULONG NumberOfBytes
)
/*++
Routine Description:
This function returns the address of the noncached extension for the
miniport driver.
Arguments:
DeviceExtension - Supplies a pointer to the miniports device extension.
ConfigInfo - Supplies a pointer to the partially initialized configuraiton
information. This is used to get an DMA adapter object.
NumberOfBytes - Supplies the size of the extension which needs to be
allocated
Return Value:
A pointer to the noncached device extension or
NULL if the requested extension size is larger than the extension
that was previously allocated.
--*/
{
if (DeviceExtension->NonCachedExtensionSize >= NumberOfBytes) {
return DeviceExtension->NonCachedExtension;
} else {
DebugPrint((0,
"ScsiPortGetUncachedExtension: Request %x but only %x available\n",
NumberOfBytes,
DeviceExtension->NonCachedExtensionSize));
return NULL;
}
}
ULONG
ScsiPortGetBusData(
IN PVOID DeviceExtension,
IN ULONG BusDataType,
IN ULONG SystemIoBusNumber,
IN ULONG SlotNumber,
IN PVOID Buffer,
IN ULONG Length
)
/*++
Routine Description:
The function returns the bus data for an adapter slot or CMOS address.
Arguments:
BusDataType - Supplies the type of bus.
BusNumber - Indicates which bus.
Buffer - Supplies the space to store the data.
Length - Supplies a count in bytes of the maximum amount to return.
Return Value:
Returns the amount of data stored into the buffer.
--*/
{
ULONG ret;
//
// If the length is non-zero, the the requested data.
//
if (BusDataType == PCIConfiguration) {
ret = HalGetBusDataByOffset(
BusDataType,
SystemIoBusNumber,
SlotNumber,
Buffer,
0,
Length);
} else {
ret = 0;
}
return ret;
}
PSCSI_REQUEST_BLOCK
ScsiPortGetSrb(
IN PVOID HwDeviceExtension,
IN UCHAR PathId,
IN UCHAR TargetId,
IN UCHAR Lun,
IN LONG QueueTag
)
/*++
Routine Description:
This routine retrieves an active SRB for a particuliar logical unit.
Arguments:
HwDeviceExtension -
PathId -
TargetId -
Lun - identify logical unit on SCSI bus.
QueueTag - -1 indicates request is not tagged.
Return Value:
SRB if outstanding request, otherwise NULL.
--*/
{
PSCSI_REQUEST_BLOCK srb;
if (DeviceExtension->RequestPending) {
srb = &DeviceExtension->Srb;
} else {
srb = NULL;
}
return srb;
}
BOOLEAN
ScsiPortValidateRange(
IN PVOID HwDeviceExtension,
IN INTERFACE_TYPE BusType,
IN ULONG SystemIoBusNumber,
IN SCSI_PHYSICAL_ADDRESS IoAddress,
IN ULONG NumberOfBytes,
IN BOOLEAN InIoSpace
)
/*++
Routine Description:
This routine should take an IO range and make sure that it is not already
in use by another adapter. This allows miniport drivers to probe IO where
an adapter could be, without worrying about messing up another card.
Arguments:
HwDeviceExtension - Used to find scsi managers internal structures
BusType - EISA, PCI, PC/MCIA, MCA, ISA, what?
SystemIoBusNumber - Which system bus?
IoAddress - Start of range
NumberOfBytes - Length of range
InIoSpace - Is range in IO space?
Return Value:
TRUE if range not claimed by another driver.
--*/
{
//
// This is not implemented in NT.
//
return TRUE;
}
VOID
ScsiPortReadPortBufferUchar(
IN PUCHAR Port,
IN PUCHAR Buffer,
IN ULONG Count
)
/*++
Routine Description:
Read a buffer of unsigned bytes from the specified port address.
Arguments:
Port - Supplies a pointer to the port address.
Buffer - Supplies a pointer to the data buffer area.
Count - The count of items to move.
Return Value:
None
--*/
{
READ_PORT_BUFFER_UCHAR(Port, Buffer, Count);
}
VOID
ScsiPortReadPortBufferUshort(
IN PUSHORT Port,
IN PUSHORT Buffer,
IN ULONG Count
)
/*++
Routine Description:
Read a buffer of unsigned shorts from the specified port address.
Arguments:
Port - Supplies a pointer to the port address.
Buffer - Supplies a pointer to the data buffer area.
Count - The count of items to move.
Return Value:
None
--*/
{
READ_PORT_BUFFER_USHORT(Port, Buffer, Count);
}
VOID
ScsiPortReadPortBufferUlong(
IN PULONG Port,
IN PULONG Buffer,
IN ULONG Count
)
/*++
Routine Description:
Read a buffer of unsigned longs from the specified port address.
Arguments:
Port - Supplies a pointer to the port address.
Buffer - Supplies a pointer to the data buffer area.
Count - The count of items to move.
Return Value:
None
--*/
{
READ_PORT_BUFFER_ULONG(Port, Buffer, Count);
}
VOID
ScsiPortWritePortBufferUchar(
IN PUCHAR Port,
IN PUCHAR Buffer,
IN ULONG Count
)
/*++
Routine Description:
Write a buffer of unsigned bytes from the specified port address.
Arguments:
Port - Supplies a pointer to the port address.
Buffer - Supplies a pointer to the data buffer area.
Count - The count of items to move.
Return Value:
None
--*/
{
WRITE_PORT_BUFFER_UCHAR(Port, Buffer, Count);
}
VOID
ScsiPortWritePortBufferUshort(
IN PUSHORT Port,
IN PUSHORT Buffer,
IN ULONG Count
)
/*++
Routine Description:
Write a buffer of unsigned shorts from the specified port address.
Arguments:
Port - Supplies a pointer to the port address.
Buffer - Supplies a pointer to the data buffer area.
Count - The count of items to move.
Return Value:
None
--*/
{
WRITE_PORT_BUFFER_USHORT(Port, Buffer, Count);
}
VOID
ScsiPortWritePortBufferUlong(
IN PULONG Port,
IN PULONG Buffer,
IN ULONG Count
)
/*++
Routine Description:
Write a buffer of unsigned longs from the specified port address.
Arguments:
Port - Supplies a pointer to the port address.
Buffer - Supplies a pointer to the data buffer area.
Count - The count of items to move.
Return Value:
None
--*/
{
WRITE_PORT_BUFFER_ULONG(Port, Buffer, Count);
}
ULONG
ScsiPortSetBusDataByOffset(
IN PVOID DeviceExtension,
IN ULONG BusDataType,
IN ULONG SystemIoBusNumber,
IN ULONG SlotNumber,
IN PVOID Buffer,
IN ULONG Offset,
IN ULONG Length
)
/*++
Routine Description:
The function returns writes bus data to a specific offset within a slot.
Arguments:
DeviceExtension - State information for a particular adapter.
BusDataType - Supplies the type of bus.
SystemIoBusNumber - Indicates which system IO bus.
SlotNumber - Indicates which slot.
Buffer - Supplies the data to write.
Offset - Byte offset to begin the write.
Length - Supplies a count in bytes of the maximum amount to return.
Return Value:
Number of bytes written.
--*/
{
return 0;
return(HalSetBusDataByOffset(BusDataType,
SystemIoBusNumber,
SlotNumber,
Buffer,
Offset,
Length));
}
BOOLEAN
ResetBus(
IN PDEVICE_EXTENSION DeviceExtension,
IN ULONG PathId
)
/*++
Routine Description:
This function will call the miniport's reset routine, and stall for 4 seconds
before continuing
Arguments:
DeviceExtension - State information for a particular adapter.
Pathid - Identifies the SCSI bus to reset
--*/
{
BOOLEAN result;
ASSERT ( DeviceExtension != NULL );
ASSERT ( DeviceExtension->HwReset != NULL );
result = DeviceExtension->HwReset ( DeviceExtension->HwDeviceExtension, PathId );
//
// Wait for 4 seconds
//
DeviceExtension->StallRoutine( RESET_DELAY );
//
// Poll the interrupt handler to clear any reset interrupts.
//
if (DeviceExtension->HwInterrupt != NULL) {
DeviceExtension->HwInterrupt(DeviceExtension->HwDeviceExtension);
}
return result;
}
VOID
ScsiPortQuerySystemTime(
OUT PLARGE_INTEGER Time
)
{
Time->QuadPart = 0;
}
BOOLEAN
StorPortDeviceBusy(
IN PVOID HwDeviceExtension,
IN UCHAR PathId,
IN UCHAR TargetId,
IN UCHAR Lun,
IN ULONG RequestsToComplete
)
{
return TRUE;
}
BOOLEAN
StorPortDeviceReady(
IN PVOID HwDeviceExtension,
IN UCHAR PathId,
IN UCHAR TargetId,
IN UCHAR Lun
)
{
return TRUE;
}
PSTOR_SCATTER_GATHER_LIST
StorPortGetScatterGatherList(
IN PVOID HwDeviceExtension,
IN PSCSI_REQUEST_BLOCK Srb
)
{
// NB: Check that SG list count is correct
return (PSTOR_SCATTER_GATHER_LIST)&DeviceExtension->ScatterGatherList;
}
BOOLEAN
StorPortResumeDevice(
IN PVOID HwDeviceExtension,
IN UCHAR PathId,
IN UCHAR TargetId,
IN UCHAR Lun
)
{
return TRUE;
}
BOOLEAN
StorPortBusy(
IN PVOID HwDeviceExtension,
IN ULONG RequestsToComplete
)
{
return TRUE;
}
BOOLEAN
StorPortReady(
IN PVOID HwDeviceExtension
)
{
return TRUE;
}
BOOLEAN
StorPortPause(
IN PVOID HwDeviceExtension,
IN ULONG Timeout
)
{
ScsiPortStallExecution (Timeout * SECONDS);
return TRUE;
}
BOOLEAN
StorPortPauseDevice(
IN PVOID HwDeviceExtension,
IN UCHAR PathId,
IN UCHAR TargetId,
IN UCHAR Lun,
IN ULONG Timeout
)
{
ScsiPortStallExecution (Timeout * SECONDS);
return TRUE;
}
BOOLEAN
StorPortResume(
IN PVOID HwDeviceExtension
)
{
return TRUE;
}
BOOLEAN
StorPortSynchronizeAccess(
IN PVOID HwDeviceExtension,
IN PSTOR_SYNCHRONIZED_ACCESS SynchronizedAccessRoutine,
IN PVOID Context
)
{
ASSERT (SynchronizedAccessRoutine != NULL);
return SynchronizedAccessRoutine (HwDeviceExtension, Context);
}
//
// DEAD CODE: The remainder of this file is no longer used.
//
#if 0
//
// The functions ReadSector() and IssueReadCapacity() are
// no longer necessary. They are left here for reference purposes
// only
//
VOID
ReadSector(
PLARGE_INTEGER ByteOffset
)
/*++
Routine Description:
Read 1 sector into common buffer.
Arguments:
None.
Return Value:
None.
--*/
{
PSCSI_REQUEST_BLOCK srb = &DeviceExtension->Srb;
PCDB cdb = (PCDB)&srb->Cdb;
ULONG startingSector;
ULONG retryCount = 0;
PPFN_NUMBER page;
PFN_NUMBER localMdl[(sizeof( MDL )/sizeof(PFN_NUMBER)) + (MAXIMUM_TRANSFER_SIZE / PAGE_SIZE) + 2];
//
// Zero SRB.
//
RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
readSectorRetry:
//
// Initialize SRB.
//
srb->Length = sizeof(SCSI_REQUEST_BLOCK);
srb->PathId = DeviceExtension->PathId;
srb->TargetId = DeviceExtension->TargetId;
srb->Lun = DeviceExtension->Lun;
srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
srb->SrbFlags = SRB_FLAGS_DATA_IN |
SRB_FLAGS_DISABLE_SYNCH_TRANSFER |
SRB_FLAGS_DISABLE_DISCONNECT |
SRB_FLAGS_DISABLE_AUTOSENSE;
srb->SrbStatus = srb->ScsiStatus = 0;
srb->NextSrb = 0;
srb->TimeOutValue = 5;
srb->CdbLength = 10;
srb->DataBuffer = DeviceExtension->CommonBuffer[1];
srb->DataTransferLength = DeviceExtension->BytesPerSector;
//
// Build MDL and map it so that it can be used.
//
DeviceExtension->Mdl = (PMDL)&localMdl[0];
MmInitializeMdl(DeviceExtension->Mdl,
srb->DataBuffer,
srb->DataTransferLength);
page = MdlGetMdlPfnArray ( DeviceExtension->Mdl );
*page = (PFN_NUMBER)(DeviceExtension->PhysicalAddress[1].QuadPart >> PAGE_SHIFT);
MmMapMemoryDumpMdl(DeviceExtension->Mdl);
//
// Initialize CDB for READ command.
//
cdb->CDB10.OperationCode = SCSIOP_READ;
//
// Calculate starting sector.
//
startingSector = (ULONG)((*ByteOffset).QuadPart /
DeviceExtension->BytesPerSector);
//
// SCSI CDBs use big endian.
//
cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&startingSector)->Byte3;
cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&startingSector)->Byte2;
cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&startingSector)->Byte1;
cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&startingSector)->Byte0;
cdb->CDB10.TransferBlocksMsb = 0;
cdb->CDB10.TransferBlocksLsb = 1;
//
// Send SRB to miniport driver.
//
ExecuteSrb(srb);
if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS &&
SRB_STATUS(srb->SrbStatus) != SRB_STATUS_DATA_OVERRUN) {
DebugPrint((1,
"ReadSector: Read sector failed SRB status %x\n",
srb->SrbStatus));
if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SELECTION_TIMEOUT &&
retryCount < 2) {
//
// If the selection did not time out then retry the request.
//
retryCount++;
goto readSectorRetry;
}
}
}
#endif
UCHAR
StorPortReadPortUchar(
IN PVOID HwDeviceExtension,
IN PUCHAR Port
)
/*++
Routine Description:
Read from the specified port address.
Arguments:
Port - Supplies a pointer to the port address.
Return Value:
Returns the value read from the specified port address.
--*/
{
return(READ_PORT_UCHAR(Port));
}
USHORT
StorPortReadPortUshort(
IN PVOID HwDeviceExtension,
IN PUSHORT Port
)
/*++
Routine Description:
Read from the specified port address.
Arguments:
Port - Supplies a pointer to the port address.
Return Value:
Returns the value read from the specified port address.
--*/
{
return(READ_PORT_USHORT(Port));
}
ULONG
StorPortReadPortUlong(
IN PVOID HwDeviceExtension,
IN PULONG Port
)
/*++
Routine Description:
Read from the specified port address.
Arguments:
Port - Supplies a pointer to the port address.
Return Value:
Returns the value read from the specified port address.
--*/
{
return(READ_PORT_ULONG(Port));
}
VOID
StorPortReadPortBufferUchar(
IN PVOID HwDeviceExtension,
IN PUCHAR Port,
IN PUCHAR Buffer,
IN ULONG Count
)
/*++
Routine Description:
Read a buffer of unsigned bytes from the specified port address.
Arguments:
Port - Supplies a pointer to the port address.
Buffer - Supplies a pointer to the data buffer area.
Count - The count of items to move.
Return Value:
None
--*/
{
READ_PORT_BUFFER_UCHAR(Port, Buffer, Count);
}
VOID
StorPortReadPortBufferUshort(
IN PVOID HwDeviceExtension,
IN PUSHORT Port,
IN PUSHORT Buffer,
IN ULONG Count
)
/*++
Routine Description:
Read a buffer of unsigned shorts from the specified port address.
Arguments:
Port - Supplies a pointer to the port address.
Buffer - Supplies a pointer to the data buffer area.
Count - The count of items to move.
Return Value:
None
--*/
{
READ_PORT_BUFFER_USHORT(Port, Buffer, Count);
}
VOID
StorPortReadPortBufferUlong(
IN PVOID HwDeviceExtension,
IN PULONG Port,
IN PULONG Buffer,
IN ULONG Count
)
/*++
Routine Description:
Read a buffer of unsigned longs from the specified port address.
Arguments:
Port - Supplies a pointer to the port address.
Buffer - Supplies a pointer to the data buffer area.
Count - The count of items to move.
Return Value:
None
--*/
{
READ_PORT_BUFFER_ULONG(Port, Buffer, Count);
}
UCHAR
StorPortReadRegisterUchar(
IN PVOID HwDeviceExtension,
IN PUCHAR Register
)
/*++
Routine Description:
Read from the specificed register address.
Arguments:
Register - Supplies a pointer to the register address.
Return Value:
Returns the value read from the specified register address.
--*/
{
return(READ_REGISTER_UCHAR(Register));
}
USHORT
StorPortReadRegisterUshort(
IN PVOID HwDeviceExtension,
IN PUSHORT Register
)
/*++
Routine Description:
Read from the specified register address.
Arguments:
Register - Supplies a pointer to the register address.
Return Value:
Returns the value read from the specified register address.
--*/
{
return(READ_REGISTER_USHORT(Register));
}
ULONG
StorPortReadRegisterUlong(
IN PVOID HwDeviceExtension,
IN PULONG Register
)
/*++
Routine Description:
Read from the specified register address.
Arguments:
Register - Supplies a pointer to the register address.
Return Value:
Returns the value read from the specified register address.
--*/
{
return(READ_REGISTER_ULONG(Register));
}
VOID
StorPortReadRegisterBufferUchar(
IN PVOID HwDeviceExtension,
IN PUCHAR Register,
IN PUCHAR Buffer,
IN ULONG Count
)
/*++
Routine Description:
Read a buffer of unsigned bytes from the specified register address.
Arguments:
Register - Supplies a pointer to the port address.
Buffer - Supplies a pointer to the data buffer area.
Count - The count of items to move.
Return Value:
None
--*/
{
READ_REGISTER_BUFFER_UCHAR(Register, Buffer, Count);
}
VOID
StorPortReadRegisterBufferUshort(
IN PVOID HwDeviceExtension,
IN PUSHORT Register,
IN PUSHORT Buffer,
IN ULONG Count
)
/*++
Routine Description:
Read a buffer of unsigned shorts from the specified register address.
Arguments:
Register - Supplies a pointer to the port address.
Buffer - Supplies a pointer to the data buffer area.
Count - The count of items to move.
Return Value:
None
--*/
{
READ_REGISTER_BUFFER_USHORT(Register, Buffer, Count);
}
VOID
StorPortReadRegisterBufferUlong(
IN PVOID HwDeviceExtension,
IN PULONG Register,
IN PULONG Buffer,
IN ULONG Count
)
/*++
Routine Description:
Read a buffer of unsigned longs from the specified register address.
Arguments:
Register - Supplies a pointer to the port address.
Buffer - Supplies a pointer to the data buffer area.
Count - The count of items to move.
Return Value:
None
--*/
{
READ_REGISTER_BUFFER_ULONG(Register, Buffer, Count);
}
VOID
StorPortWritePortUchar(
IN PVOID HwDeviceExtension,
IN PUCHAR Port,
IN UCHAR Value
)
/*++
Routine Description:
Write to the specificed port address.
Arguments:
Port - Supplies a pointer to the port address.
Value - Supplies the value to be written.
Return Value:
None
--*/
{
WRITE_PORT_UCHAR(Port, Value);
}
VOID
StorPortWritePortUshort(
IN PVOID HwDeviceExtension,
IN PUSHORT Port,
IN USHORT Value
)
/*++
Routine Description:
Write to the specificed port address.
Arguments:
Port - Supplies a pointer to the port address.
Value - Supplies the value to be written.
Return Value:
None
--*/
{
WRITE_PORT_USHORT(Port, Value);
}
VOID
StorPortWritePortUlong(
IN PVOID HwDeviceExtension,
IN PULONG Port,
IN ULONG Value
)
/*++
Routine Description:
Write to the specificed port address.
Arguments:
Port - Supplies a pointer to the port address.
Value - Supplies the value to be written.
Return Value:
None
--*/
{
WRITE_PORT_ULONG(Port, Value);
}
VOID
StorPortWritePortBufferUchar(
IN PVOID HwDeviceExtension,
IN PUCHAR Port,
IN PUCHAR Buffer,
IN ULONG Count
)
/*++
Routine Description:
Write a buffer of unsigned bytes from the specified port address.
Arguments:
Port - Supplies a pointer to the port address.
Buffer - Supplies a pointer to the data buffer area.
Count - The count of items to move.
Return Value:
None
--*/
{
WRITE_PORT_BUFFER_UCHAR(Port, Buffer, Count);
}
VOID
StorPortWritePortBufferUshort(
IN PVOID HwDeviceExtension,
IN PUSHORT Port,
IN PUSHORT Buffer,
IN ULONG Count
)
/*++
Routine Description:
Write a buffer of unsigned shorts from the specified port address.
Arguments:
Port - Supplies a pointer to the port address.
Buffer - Supplies a pointer to the data buffer area.
Count - The count of items to move.
Return Value:
None
--*/
{
WRITE_PORT_BUFFER_USHORT(Port, Buffer, Count);
}
VOID
StorPortWritePortBufferUlong(
IN PVOID HwDeviceExtension,
IN PULONG Port,
IN PULONG Buffer,
IN ULONG Count
)
/*++
Routine Description:
Write a buffer of unsigned longs from the specified port address.
Arguments:
Port - Supplies a pointer to the port address.
Buffer - Supplies a pointer to the data buffer area.
Count - The count of items to move.
Return Value:
None
--*/
{
WRITE_PORT_BUFFER_ULONG(Port, Buffer, Count);
}
VOID
StorPortWriteRegisterUchar(
IN PVOID HwDeviceExtension,
IN PUCHAR Register,
IN UCHAR Value
)
/*++
Routine Description:
Write to the specificed register address.
Arguments:
Register - Supplies a pointer to the register address.
Value - Supplies the value to be written.
Return Value:
None
--*/
{
WRITE_REGISTER_UCHAR(Register, Value);
}
VOID
StorPortWriteRegisterUshort(
IN PVOID HwDeviceExtension,
IN PUSHORT Register,
IN USHORT Value
)
/*++
Routine Description:
Write to the specificed register address.
Arguments:
Register - Supplies a pointer to the register address.
Value - Supplies the value to be written.
Return Value:
None
--*/
{
WRITE_REGISTER_USHORT(Register, Value);
}
VOID
StorPortWriteRegisterBufferUchar(
IN PVOID HwDeviceExtension,
IN PUCHAR Register,
IN PUCHAR Buffer,
IN ULONG Count
)
/*++
Routine Description:
Write a buffer of unsigned bytes from the specified register address.
Arguments:
Register - Supplies a pointer to the port address.
Buffer - Supplies a pointer to the data buffer area.
Count - The count of items to move.
Return Value:
None
--*/
{
WRITE_REGISTER_BUFFER_UCHAR(Register, Buffer, Count);
}
VOID
StorPortWriteRegisterBufferUshort(
IN PVOID HwDeviceExtension,
IN PUSHORT Register,
IN PUSHORT Buffer,
IN ULONG Count
)
/*++
Routine Description:
Write a buffer of unsigned shorts from the specified register address.
Arguments:
Register - Supplies a pointer to the port address.
Buffer - Supplies a pointer to the data buffer area.
Count - The count of items to move.
Return Value:
None
--*/
{
WRITE_REGISTER_BUFFER_USHORT(Register, Buffer, Count);
}
VOID
StorPortWriteRegisterBufferUlong(
IN PVOID HwDeviceExtension,
IN PULONG Register,
IN PULONG Buffer,
IN ULONG Count
)
/*++
Routine Description:
Write a buffer of unsigned longs from the specified register address.
Arguments:
Register - Supplies a pointer to the port address.
Buffer - Supplies a pointer to the data buffer area.
Count - The count of items to move.
Return Value:
None
--*/
{
WRITE_REGISTER_BUFFER_ULONG(Register, Buffer, Count);
}
VOID
StorPortWriteRegisterUlong(
IN PVOID HwDeviceExtension,
IN PULONG Register,
IN ULONG Value
)
/*++
Routine Description:
Write to the specificed register address.
Arguments:
Register - Supplies a pointer to the register address.
Value - Supplies the value to be written.
Return Value:
None
--*/
{
WRITE_REGISTER_ULONG(Register, Value);
}
PUCHAR
StorPortAllocateRegistryBuffer(
IN PVOID HwDeviceExtension,
IN PULONG Length
)
{
return NULL;
}
VOID
StorPortFreeRegistryBuffer(
IN PVOID HwDeviceExtension,
IN PUCHAR Buffer
)
{
}
BOOLEAN
StorPortRegistryRead(
IN PVOID HwDeviceExtension,
IN PUCHAR ValueName,
IN ULONG Global,
IN ULONG Type,
IN PUCHAR Buffer,
IN PULONG BufferLength
)
{
return FALSE;
}
BOOLEAN
StorPortRegistryWrite(
IN PVOID HwDeviceExtension,
IN PUCHAR ValueName,
IN ULONG Global,
IN ULONG Type,
IN PUCHAR Buffer,
IN ULONG BufferLength
)
{
return FALSE;
}
BOOLEAN
StorPortSetDeviceQueueDepth(
IN PVOID HwDeviceExtension,
IN UCHAR PathId,
IN UCHAR TargetId,
IN UCHAR Lun,
IN ULONG Depth
)
{
return TRUE;
}