1641 lines
49 KiB
C
1641 lines
49 KiB
C
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (c) 1992 NCR Corporation
|
|
//
|
|
// NCRSDMS.C
|
|
//
|
|
// This is the Windows NT NCR MiniPort driver for all NCR CAMcores.
|
|
//
|
|
// Revisions:
|
|
//
|
|
//
|
|
// Note: Search for the word "future" for things that may need to
|
|
// be upgraded for SDMS 3.0 or to support other enhanced
|
|
// features.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// NT include files
|
|
|
|
#include "miniport.h" // MiniPort structure definitions
|
|
#include "scsi.h" // SRB & SCSI structure definitions and others
|
|
|
|
#ifdef i386
|
|
|
|
// NCR SDMS include files
|
|
|
|
#include "typedefs.h" // Defines for uchar,ushort,ulong etc.
|
|
#include "camcore.h" // CAMCore ROM header structure definition
|
|
#include "camglbls.h" // Globals structure definitions
|
|
#include "intercam.h" // ROMCCB structure definitions, additional
|
|
// fields used in ROM appended to end of
|
|
// CAM CCB. Also, includes cam.h which
|
|
// defines CAM CCB structures.
|
|
|
|
|
|
#include "ncrsdms.h" // Specific info for the miniport driver.
|
|
|
|
// Noncached Extension - Guarantees to be below the 16MB 24 bit addressing
|
|
// limitation of AT cards. Need this for CoreGlobals which contain
|
|
// SCRIPT instructions for the C700 family. Must fetch below the
|
|
// 16MB limit for AT cards. Note: Fujitsu EISA board also has this
|
|
// limitation.
|
|
|
|
typedef struct _NONCACHED_EXTENSION{
|
|
|
|
CAMGlobals CoreGlobals; // CAMGlobals structure defined in CAMGLBLS.H
|
|
|
|
UCHAR SCSICoreGlobals[4096];
|
|
// This is to make room for the globals
|
|
// defined in SCSICORE for each chip.
|
|
// For example, C700 SCRIPTS and misc.
|
|
// other globals. Defined in SCSIcore.h
|
|
// for each chips camcore.
|
|
|
|
} NONCACHED_EXTENSION, *PNONCACHED_EXTENSION;
|
|
|
|
// Hardware device extension.
|
|
// This structure is initialized in the FindCore routine.
|
|
|
|
|
|
typedef struct _HW_DEVICE_EXTENSION {
|
|
|
|
// Pointer to noncached extension
|
|
|
|
PNONCACHED_EXTENSION NoncachedExtension;
|
|
|
|
// The next set of functions MUST be defined as type "_cdecl".
|
|
// These functions are in the CAMcore and have been previously
|
|
// compiled as "_cdecl" type functions, while NT assumes all
|
|
// functions are "_stdcall". The difference is in which type of
|
|
// function adjusts the stack - caller adjusts when using _cdecl
|
|
// while callee adjusts stack when using _stdcall.
|
|
|
|
// Pointer to CAMInit in 32-bit CAMcore code.
|
|
ULONG (__cdecl *initPtr)(PVOID CoreGlobalsPtr);
|
|
|
|
// Pointer to CAMStart in 32-bit CAMcore code.
|
|
ULONG (__cdecl *startPtr)(PVOID CoreGlobalsPtr, PVOID CCBPtr);
|
|
|
|
// Pointer to CAMInterrupt in 32-bit CAMcore code.
|
|
ULONG (__cdecl *interruptPtr)(PVOID CoreGlobalsPtr);
|
|
|
|
// Pointer to chsMap routine in stdport 32 bit CAMcore code.
|
|
VOID (__cdecl *chsPtr)(PVOID CoreGlobalsPtr, PVOID CCBPtr);
|
|
|
|
// SDMS Version number.
|
|
ULONG SdmsVersion;
|
|
|
|
// Path id of this device extension.
|
|
ULONG scsiBusId;
|
|
|
|
// Storage area for REX code.
|
|
UCHAR base32BitCode[MAX_32BIT_SIZE];
|
|
|
|
} HW_DEVICE_EXTENSION, *PHW_DEVICE_EXTENSION;
|
|
|
|
// Logical unit extension derived from the SRB
|
|
|
|
typedef struct _HW_LU_EXTENSION {
|
|
|
|
PSCSI_REQUEST_BLOCK CurrentSrb; // Current SRB
|
|
|
|
} HW_LU_EXTENSION, *PHW_LU_EXTENSION;
|
|
|
|
ULONG
|
|
DriverEntry(
|
|
IN PVOID DriverObject,
|
|
IN PVOID Argument2
|
|
);
|
|
|
|
ULONG
|
|
NCRFindAdapter(
|
|
IN PVOID DeviceExtension,
|
|
IN PVOID HwContext,
|
|
IN PVOID BusInformation,
|
|
IN PCHAR ArgumentString,
|
|
IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
|
|
OUT PBOOLEAN Again
|
|
);
|
|
|
|
BOOLEAN
|
|
NCRHwInitialize(
|
|
IN PVOID DeviceExtension
|
|
);
|
|
|
|
BOOLEAN
|
|
NCRStartIo(
|
|
IN PVOID DeviceExtension,
|
|
IN PSCSI_REQUEST_BLOCK Srb
|
|
);
|
|
|
|
BOOLEAN
|
|
NCRInterrupt(
|
|
IN PVOID DeviceExtension
|
|
);
|
|
|
|
BOOLEAN
|
|
NCRResetBus(
|
|
IN PVOID DeviceExtension,
|
|
IN ULONG PathId
|
|
);
|
|
|
|
ULONG
|
|
FindCore(
|
|
IN PHW_DEVICE_EXTENSION DeviceExtension,
|
|
IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
|
|
IN OUT PHWInfo hwInfo,
|
|
OUT PBOOLEAN Again
|
|
);
|
|
|
|
VOID
|
|
InitPath(
|
|
IN PHW_DEVICE_EXTENSION DeviceExtension
|
|
);
|
|
|
|
VOID
|
|
BuildCCBFromSRB(
|
|
IN PHW_DEVICE_EXTENSION DeviceExtension,
|
|
IN PSCSI_REQUEST_BLOCK Srb
|
|
);
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// DriverEntry
|
|
//
|
|
// Installable driver initialization entry point for system.
|
|
// 1) Initialize hwInitializationData structure
|
|
// 2) Call ScsiPortInitialize routine in PortDriver
|
|
//
|
|
// Arguments:
|
|
// Argument1 - supplies a context value with
|
|
// which the HBA miniport driver should call
|
|
// ScsiPortInitialize.
|
|
//
|
|
// Argument2 - supplies a 2nd context value with
|
|
// which the HBA miniport driver should call
|
|
// ScsiPortInitialize.
|
|
//
|
|
// Return Value: status returned by ScsiPortInitialize
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
ULONG
|
|
DriverEntry(
|
|
IN PVOID DriverObject,
|
|
IN PVOID Argument2
|
|
)
|
|
{
|
|
HW_INITIALIZATION_DATA hwInitData;
|
|
|
|
HWInfo hwInfo;
|
|
|
|
ULONG isaStatus;
|
|
ULONG eisaStatus;
|
|
ULONG mcaStatus;
|
|
ULONG internalStatus;
|
|
ULONG busStatus;
|
|
ULONG i;
|
|
|
|
DebugPrint(( 1, "NCR SDMS: DriverEntry \n"));
|
|
|
|
// Zero out structure
|
|
|
|
for ( i = 0 ; i < sizeof(HW_INITIALIZATION_DATA); i++ ) {
|
|
((PUCHAR)&hwInitData)[i] = 0;
|
|
}
|
|
|
|
// Set size of hwInitData
|
|
|
|
hwInitData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
|
|
|
|
// Initialize entry points to MiniPort routines
|
|
|
|
hwInitData.HwInitialize = NCRHwInitialize;
|
|
hwInitData.HwStartIo = NCRStartIo;
|
|
hwInitData.HwInterrupt = NCRInterrupt;
|
|
hwInitData.HwFindAdapter = NCRFindAdapter;
|
|
hwInitData.HwResetBus = NCRResetBus;
|
|
|
|
// Following MiniPort routines not supported.
|
|
hwInitData.HwDmaStarted = NULL;
|
|
|
|
// Size in bytes required to hold per adapter information.
|
|
hwInitData.DeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION);
|
|
|
|
// Specify size (bytes) of per logical unit storage.
|
|
hwInitData.SpecificLuExtensionSize = 0;
|
|
|
|
// Specify size (bytes) of the per request storage.
|
|
// Setting extension size to zero causes a crash in FindCore when
|
|
// ScsiPortGetUncachedExtension is called. Why????
|
|
|
|
hwInitData.SrbExtensionSize = sizeof( ROMscsiCCB );
|
|
|
|
// Initialize access range from CAMcore ROM header
|
|
// (I/O and/or memory mapped locations) normally 2 for now.
|
|
// Future: We have to allow for I/O, Memory-mapped,
|
|
// or both because we do not know anything about the
|
|
// adapter at this point.
|
|
hwInitData.NumberOfAccessRanges = 2;
|
|
|
|
hwInitData.MapBuffers = FALSE;
|
|
|
|
hwInitData.NeedPhysicalAddresses = TRUE;
|
|
|
|
// Initial release does not support tagged queing.
|
|
hwInitData.TaggedQueuing = FALSE;
|
|
|
|
// Auto request sense not enabled. The SRB will still attempt to
|
|
// enable this function, so auto request sense must also be disabled
|
|
// at the CCB level.
|
|
hwInitData.AutoRequestSense = FALSE;
|
|
|
|
hwInitData.MultipleRequestPerLu = FALSE;
|
|
|
|
hwInitData.ReceiveEvent = FALSE;
|
|
|
|
// Reset the HBA count.
|
|
hwInfo.hbaCount = 0;
|
|
|
|
// Track how many adapter addresses have been checked for validity.
|
|
// This variable also referred to as "HwContext" or "Context" in
|
|
// the FindAdapter routine.
|
|
|
|
// Try to configure for EISA.
|
|
|
|
DebugPrint(( 2, "NCR SDMS: DriverEntry *** EISA *** \n" ));
|
|
|
|
hwInfo.romAddrSpace = 0;
|
|
hwInfo.currentVirtAddr = 0;
|
|
hwInfo.currentRomAddr = FIRST_ROM_ADDRESS;
|
|
hwInfo.scsiBusId = 0;
|
|
hwInitData.AdapterInterfaceType = Eisa;
|
|
|
|
eisaStatus = ScsiPortInitialize(DriverObject, Argument2,
|
|
&hwInitData, &hwInfo);
|
|
|
|
DebugPrint(( 3, "NCR SDMS: DriverEntry ...eisaStatus = 0x%x \n",
|
|
eisaStatus ));
|
|
|
|
if ( hwInfo.hbaCount < MAX_NT_HBAS && eisaStatus != 0 )
|
|
{
|
|
DebugPrint(( 2, "NCR SDMS: DriverEntry *** ISA *** \n" ));
|
|
|
|
hwInfo.romAddrSpace = 0;
|
|
hwInfo.currentVirtAddr = 0;
|
|
hwInfo.currentRomAddr = FIRST_ROM_ADDRESS;
|
|
hwInfo.scsiBusId = 0;
|
|
hwInitData.AdapterInterfaceType = Isa;
|
|
|
|
isaStatus = ScsiPortInitialize(DriverObject, Argument2,
|
|
&hwInitData, &hwInfo);
|
|
|
|
DebugPrint(( 3, "NCR SDMS: DriverEntry ...isaStatus = 0x%x \n",
|
|
isaStatus ));
|
|
|
|
}
|
|
|
|
|
|
// Try to configure for internal (what is Internal???)
|
|
|
|
if ( hwInfo.hbaCount < MAX_NT_HBAS )
|
|
{
|
|
DebugPrint(( 2, "NCR SDMS: DriverEntry *** Internal *** \n" ));
|
|
|
|
hwInfo.romAddrSpace = 0;
|
|
hwInfo.currentVirtAddr = 0;
|
|
hwInfo.currentRomAddr = FIRST_ROM_ADDRESS;
|
|
hwInfo.scsiBusId = 0;
|
|
hwInitData.AdapterInterfaceType = Internal;
|
|
|
|
internalStatus = ScsiPortInitialize(DriverObject, Argument2,
|
|
&hwInitData, &hwInfo);
|
|
|
|
DebugPrint(( 3, "NCR SDMS: DriverEntry ...internalStatus = 0x%x \n",
|
|
internalStatus ));
|
|
}
|
|
|
|
// Try to configure for Microchannel.
|
|
|
|
if ( hwInfo.hbaCount < MAX_NT_HBAS )
|
|
{
|
|
DebugPrint(( 2, "NCR SDMS: DriverEntry *** Microchannel *** \n"));
|
|
|
|
hwInfo.romAddrSpace = 0;
|
|
hwInfo.currentVirtAddr = 0;
|
|
hwInfo.currentRomAddr = FIRST_ROM_ADDRESS;
|
|
hwInfo.scsiBusId = 0;
|
|
hwInitData.AdapterInterfaceType = MicroChannel;
|
|
|
|
mcaStatus = ScsiPortInitialize(DriverObject, Argument2,
|
|
&hwInitData, &hwInfo);
|
|
|
|
DebugPrint(( 3, "NCR SDMS: DriverEntry ...mcaStatus = 0x%x \n",
|
|
mcaStatus ));
|
|
}
|
|
|
|
// Return the minimum value.
|
|
if ( eisaStatus < isaStatus )
|
|
busStatus = eisaStatus;
|
|
else
|
|
busStatus = isaStatus;
|
|
|
|
if (internalStatus < busStatus )
|
|
busStatus = internalStatus;
|
|
|
|
if ( mcaStatus < busStatus )
|
|
busStatus = mcaStatus;
|
|
|
|
// Return the smallest status.
|
|
|
|
DebugPrint(( 1, "NCR SDMS: DriverEntry ...exiting\n"));
|
|
|
|
return( busStatus );
|
|
|
|
} // End NCREntry
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// NCRFindAdapter
|
|
//
|
|
// 1). Relocate 32 bit CAMcore code.
|
|
// 2). Allocate noncachedExtension.
|
|
//
|
|
// Return:
|
|
// ROMBase - base address of where CAMCore ROM was located.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
ULONG
|
|
NCRFindAdapter(
|
|
IN PVOID HwDeviceExtension, // CAMGlobals
|
|
IN PVOID HwContext,
|
|
IN PVOID BusInformation,
|
|
IN PCHAR ArgumentString,
|
|
IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
|
|
OUT PBOOLEAN Again
|
|
)
|
|
{
|
|
PHW_DEVICE_EXTENSION DeviceExtension = HwDeviceExtension;
|
|
PNONCACHED_EXTENSION noncachedExtension;
|
|
ULONG FCReturnValue;
|
|
PHWInfo hwInfo;
|
|
|
|
|
|
DebugPrint(( 1, "NCR SDMS: NCRFindAdapter \n" ));
|
|
|
|
// Need to get some information about previous calls.
|
|
hwInfo = (PHWInfo)HwContext;
|
|
|
|
// Check if the ROM address space has been mapped yet.
|
|
// If not, map the entire ROM address space in one call --
|
|
// this is to prevent a problem with NTLoader running out
|
|
// of page frame entries.
|
|
if (hwInfo->romAddrSpace == 0 )
|
|
{
|
|
// Get the entire ROM address space.
|
|
hwInfo->romAddrSpace = ScsiPortGetDeviceBase(
|
|
DeviceExtension,
|
|
ConfigInfo->AdapterInterfaceType, // Bus type
|
|
ConfigInfo->SystemIoBusNumber, // Bus number
|
|
ScsiPortConvertUlongToPhysicalAddress(
|
|
FIRST_ROM_ADDRESS ),
|
|
ROM_ADDRESS_SPACE_SIZE, // Map entire ROM region
|
|
// from C0000 - FFFFF
|
|
FALSE ); // Memory mapped
|
|
|
|
// If GetDeviceBase returned a zero, there was some
|
|
// error -- return to NT.
|
|
if ( hwInfo->romAddrSpace == 0 )
|
|
{
|
|
DebugPrint(( 3, "NCR SDMS: NCRFindAdapter ...Null pointer for ROM space \n"));
|
|
return( SP_RETURN_ERROR );
|
|
}
|
|
|
|
// Setup a pointer to the current virtual address we will
|
|
// be checking form SDMS ROMs.
|
|
hwInfo->currentVirtAddr = hwInfo->romAddrSpace;
|
|
}
|
|
|
|
|
|
// Check if maximum number of HBAs found. If so, clear the
|
|
// device base (if it exists), tell NT not to call FindAdapter
|
|
// anymore, and return to NT.
|
|
|
|
if ( hwInfo->hbaCount >= MAX_NT_HBAS )
|
|
{
|
|
DebugPrint(( 3, "NCR SDMS: NCRFindAdapter ...maximum HBA count exceeded \n" ));
|
|
if ( hwInfo->romAddrSpace != 0 )
|
|
ScsiPortFreeDeviceBase( DeviceExtension, hwInfo->romAddrSpace );
|
|
|
|
*Again = FALSE;
|
|
|
|
return( SP_RETURN_NOT_FOUND );
|
|
}
|
|
|
|
DebugPrint(( 2, "NCR SDMS: NCRFindAdapter ...before FindCore \n"));
|
|
|
|
FCReturnValue = FindCore( DeviceExtension,
|
|
ConfigInfo,
|
|
HwContext,
|
|
Again );
|
|
|
|
DebugPrint(( 2, "NCR SDMS: NCRFindAdapter ...after FindCore \n"));
|
|
|
|
// If no adapter found, return status to NT.
|
|
if ( FCReturnValue != SP_RETURN_FOUND )
|
|
return ( FCReturnValue );
|
|
|
|
// Initialize CAMcore and CoreGlobals. Call CAMinit in CAMcore
|
|
// with CoreInitialized = 0 .
|
|
|
|
// Noncached Extension was allocated in FindCore. Initialize the
|
|
// extension so the ConfigInfo data structure can be set up.
|
|
noncachedExtension = DeviceExtension->NoncachedExtension;
|
|
|
|
noncachedExtension->CoreGlobals.CoreInitialized = 0;
|
|
|
|
// Call CAMInit. Delays for hardware to reset are in the CAMcore.
|
|
(*DeviceExtension->initPtr)(&noncachedExtension->CoreGlobals);
|
|
|
|
// Initialize PORT_CONFIGURATION_INFORMATION
|
|
|
|
ConfigInfo->BusInterruptLevel = noncachedExtension->CoreGlobals.IRQNum;
|
|
|
|
|
|
// Update the DMA information if changed by CAMInit.
|
|
if ( noncachedExtension->CoreGlobals.DMAChannel == 0xFF ||
|
|
noncachedExtension->CoreGlobals.DMAChannel == 0x00 )
|
|
ConfigInfo->DmaChannel = 0xFFFFFFFF;
|
|
else
|
|
ConfigInfo->DmaChannel = noncachedExtension->CoreGlobals.DMAChannel;
|
|
|
|
|
|
// ConfigInfo->MaximumTransferLength = noncachedExtension->CoreGlobals.;
|
|
|
|
// Since we are doing the DMA programming (not NT), do not have to
|
|
// set DmaWidth.
|
|
// ConfigInfo->DmaWidth = xxx;
|
|
|
|
// Currently unused:
|
|
// ConfigInfo->DmaSpeed = xxx;
|
|
|
|
// Future: possibly need to get this info from CAMcore globals to
|
|
// accomodate dual SCSI channel or more.
|
|
ConfigInfo->NumberOfBuses = 1;
|
|
ConfigInfo->InitiatorBusId[0] = noncachedExtension->CoreGlobals.HASCSIID;
|
|
|
|
// Currently unused.
|
|
// ConfigInfo->AtdiskPrimaryClaimed
|
|
// ConfigInfo->AtdiskSecondaryClaimed
|
|
|
|
// Check whether we are I/O mapped or memory mapped.
|
|
if ( noncachedExtension->CoreGlobals.BasePort )
|
|
{
|
|
// IO mapped SCSI chip.
|
|
(*ConfigInfo->AccessRanges)
|
|
[AccessRangeChipIndex].RangeInMemory = FALSE;
|
|
|
|
(*ConfigInfo->AccessRanges)[AccessRangeChipIndex].RangeStart =
|
|
ScsiPortConvertUlongToPhysicalAddress(
|
|
noncachedExtension->CoreGlobals.BasePort );
|
|
}
|
|
|
|
// Return SP_RETURN_FOUND, SP_RETURN_NOT_FOUND,
|
|
// SP_RETURN_ERROR or SP_RETURN_BAD_CONFIG.
|
|
|
|
return SP_RETURN_FOUND;
|
|
|
|
} // End NCRFindAdapter
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FindCore
|
|
//
|
|
// Locates CAMcore in the ROM BIOS address space from
|
|
// 0xC0000 to 0x100000. Initializes global values for ROM address
|
|
// (HAPhysAddr, HAVirtAddr, HARAMVirtAddr), chip addresses
|
|
// (ChipVirtAddr) and address of globals (GlobalPhysAddr).
|
|
// Allocates noncachedExtension.
|
|
//
|
|
// Arguments: HwDeviceExtension -
|
|
//
|
|
// Returns: Address of CAMcore or SP_RETURN_ERROR if it could not
|
|
// allocate noncachedExtension.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
ULONG
|
|
FindCore(
|
|
IN PHW_DEVICE_EXTENSION DeviceExtension,
|
|
IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
|
|
IN OUT PHWInfo hwInfo,
|
|
OUT PBOOLEAN Again
|
|
)
|
|
{
|
|
PNONCACHED_EXTENSION noncachedExtension;
|
|
ROMCAMcoreFields * ROMHeader;
|
|
PUCHAR basePtr;
|
|
REXHeader * rp;
|
|
CAM32Header * cp;
|
|
ULONG fileSize;
|
|
PULONG relocTable;
|
|
ULONG i;
|
|
PCHAR src;
|
|
ULONG Length;
|
|
|
|
BOOLEAN NoSdmsRom;
|
|
PULONG itemPtr;
|
|
ULONG foundRomAddr;
|
|
|
|
CONST UCHAR magicStr1[] = MAGIC_STR_1 ;
|
|
|
|
DebugPrint(( 1, "NCR SDMS: FindCore \n"));
|
|
|
|
DeviceExtension->initPtr = 0;
|
|
|
|
// Set up virtual address pointer.
|
|
basePtr = hwInfo->currentVirtAddr;
|
|
|
|
// Check the ROM address space every 2K for SDMS CAMcore.
|
|
for ( ; hwInfo->currentRomAddr < LAST_ROM_ADDRESS;
|
|
basePtr += ROM_CHECK_STEP,
|
|
hwInfo->currentRomAddr += ROM_CHECK_STEP )
|
|
{
|
|
|
|
DebugPrint(( 3, "NCR SDMS: FindCore ...VirtAddr = 0x%x RomAddr = 0x%x \n",
|
|
basePtr, hwInfo->currentRomAddr ));
|
|
|
|
|
|
// Check for ROM identifier.
|
|
if ( gByte(basePtr,MARK_55) != 0x55
|
|
|| gByte(basePtr,MARK_AA) != 0xAA )
|
|
{
|
|
continue; // Check next ROM address space.
|
|
}
|
|
|
|
// Search for ROM SIM string present in all CAMCores.
|
|
NoSdmsRom = FALSE;
|
|
|
|
// Check for the identifying string in the ROM.
|
|
for (i = 0; i < sizeof(magicStr1) - 1; i++)
|
|
{
|
|
|
|
if ( gByte(basePtr,ROM_SIM_STR+i) != magicStr1[i] )
|
|
{
|
|
NoSdmsRom = TRUE;
|
|
break; // Not SDMS ROM -- stop checking identifying
|
|
// string.
|
|
}
|
|
} // End for loop
|
|
|
|
if ( NoSdmsRom )
|
|
continue; // Check next ROM address location
|
|
|
|
// At this point, we apparently have found a SDMS CAMcore.
|
|
|
|
// Store SDMS CAMcore version.
|
|
DeviceExtension->SdmsVersion = gWord(basePtr, CORE_VERSION);
|
|
|
|
DebugPrint(( 1, "NCR SDMS: FindCore ...SDMS Version = %d \n",
|
|
DeviceExtension->SdmsVersion ));
|
|
|
|
// If V1.6 or newer CAMcore, set up pointer to REX header.
|
|
// If not at least V1.6, continue searching ROM address space.
|
|
if ( DeviceExtension->SdmsVersion >= SDMS_V16 )
|
|
{
|
|
if (gWord(basePtr,REX_OFFSET) != 0)
|
|
rp = (REXHeader *)(basePtr + gWord(basePtr,REX_OFFSET));
|
|
|
|
// Look for the REX header signature of "MQ" and end of the
|
|
// REX header = 0x0001. This should be the SDMS CAMcore.
|
|
// If this is true break out of the loop checking the
|
|
// ROM address space. If REX header not found, fall
|
|
// through to bottom of FOR loop, clear device base
|
|
// and continue checking ROM address space.
|
|
|
|
if ( ( rp->sig == 0x514D ) && (rp->ooo1 == 1) )
|
|
break;
|
|
}
|
|
|
|
// Not at SDMS V1.6 or above, so clear the saved version number.
|
|
DeviceExtension->SdmsVersion = 0;
|
|
|
|
} // End of For loop checking ROM address space.
|
|
|
|
|
|
// Check if we searched outside of ROM address space. If outside of
|
|
// ROM address space, return to caller indicating no CAMcore found.
|
|
if ( hwInfo->currentRomAddr >= LAST_ROM_ADDRESS )
|
|
{
|
|
ScsiPortFreeDeviceBase( DeviceExtension, hwInfo->romAddrSpace );
|
|
|
|
hwInfo->currentVirtAddr = 0;
|
|
hwInfo->romAddrSpace = 0;
|
|
|
|
// Entire ROM address space has been searched.
|
|
*Again = FALSE;
|
|
|
|
return( SP_RETURN_NOT_FOUND );
|
|
}
|
|
|
|
// Set found ROM address.
|
|
foundRomAddr = hwInfo->currentRomAddr;
|
|
|
|
// Increment current ROM address so next time in FindCore, search
|
|
// will start at the proper location.
|
|
hwInfo->currentRomAddr += ROM_CHECK_STEP;
|
|
|
|
// Increment current virtual pointer to next possible ROM location.
|
|
hwInfo->currentVirtAddr = basePtr + ROM_CHECK_STEP;
|
|
|
|
// Allocate a smaller device base that only includes the 32K
|
|
// ROM that we have found.
|
|
basePtr = ScsiPortGetDeviceBase(
|
|
DeviceExtension,
|
|
ConfigInfo->AdapterInterfaceType, // bus type
|
|
ConfigInfo->SystemIoBusNumber, // bus number
|
|
ScsiPortConvertUlongToPhysicalAddress( foundRomAddr ),
|
|
ROM_SIZE, // 32K allocated, must allocate
|
|
// enough to be able to access
|
|
// all of the 32 bit code.
|
|
FALSE); // Memory mapped
|
|
|
|
// Tell NT that we should be called again.
|
|
*Again = TRUE;
|
|
|
|
// At this point, we have located a SDMS V1.6 (or above) CAMcore
|
|
// and identified the REX section of the CAMcore.
|
|
|
|
// Now "basePtr" points to the ROM header and "rp" points to the REX
|
|
// header in the ROM structure, and "foundRomAddr" is the
|
|
// physical address of the ROM.
|
|
|
|
DebugPrint(( 1, "NCR SDMS: FindCore ...CAMcore found at 0x%x \n",
|
|
foundRomAddr ));
|
|
|
|
// Get information from ROM header so that we can call
|
|
// GetUncachedExtension to initialize our CoreGlobals.
|
|
// GetUncachedExtension needs DmaChannel, DmaPort, DmaSpeed,
|
|
// MaximumLength, ScatterGather, Master and NumberOfPageBreaks
|
|
// (if scatter/gather is supported) initialized in the ConfigInfo
|
|
// data structure.
|
|
|
|
// Setup pointer to ROMHeader.
|
|
|
|
ROMHeader = (ROMCAMcoreFields *)basePtr;
|
|
|
|
// Save path id in device extension (for ScsiPortNotification).
|
|
DeviceExtension->scsiBusId = hwInfo->scsiBusId;
|
|
|
|
// Save DMA channel.
|
|
if ( ROMHeader->dmachannel == 0xFF || ROMHeader->dmachannel == 0x00 )
|
|
ConfigInfo->DmaChannel = 0xFFFFFFFF;
|
|
else
|
|
ConfigInfo->DmaChannel = ROMHeader->dmachannel;
|
|
|
|
// Master is always true because the CAMcore already programs
|
|
// the DMA channel not NT.
|
|
ConfigInfo->Master = TRUE;
|
|
|
|
// Initialize maximum transfer length if maxdma is not zero.
|
|
// If maxdma is zero there is no limit so leave MaximumTransferLength
|
|
// to its default of 0xffffffff which means no limit to NT.
|
|
|
|
if ( ROMHeader->maxdma )
|
|
ConfigInfo->MaximumTransferLength = ROMHeader->maxdma;
|
|
|
|
// Do not support scatter/gather with this release of the
|
|
// driver.
|
|
ConfigInfo->ScatterGather = FALSE;
|
|
|
|
// Only one break without scatter/gather. However, changing
|
|
// this to one causes run time errors -- so leave at 16 for now.
|
|
ConfigInfo->NumberOfPhysicalBreaks = MAX_SG_BRKS;
|
|
|
|
// In future to support caching adapters (CachesData=TRUE)
|
|
// we need this info in CAMcore globals or ROM header.
|
|
ConfigInfo->CachesData = FALSE;
|
|
ConfigInfo->Length = sizeof( PORT_CONFIGURATION_INFORMATION );
|
|
|
|
if ( ( gByte( basePtr, ROM_TYPE_1 ) == 'A' ) &&
|
|
( gByte( basePtr, ROM_TYPE_2 ) == 'T' ) )
|
|
{
|
|
// Insure that data buffers are below 16MB.
|
|
ConfigInfo->InterruptMode = Latched;
|
|
ConfigInfo->Dma32BitAddresses = FALSE;
|
|
}
|
|
else
|
|
{
|
|
ConfigInfo->InterruptMode = LevelSensitive;
|
|
ConfigInfo->Dma32BitAddresses = TRUE;
|
|
}
|
|
|
|
// Allocate a Noncached Extension to use for CoreGlobals.
|
|
|
|
DeviceExtension->NoncachedExtension = ScsiPortGetUncachedExtension(
|
|
DeviceExtension,
|
|
ConfigInfo,
|
|
sizeof(NONCACHED_EXTENSION));
|
|
|
|
noncachedExtension = DeviceExtension->NoncachedExtension;
|
|
|
|
// If Noncached extension could not be allocated, log error.
|
|
if (DeviceExtension->NoncachedExtension == NULL)
|
|
{
|
|
ScsiPortLogError( DeviceExtension,
|
|
NULL,
|
|
0,
|
|
0,
|
|
0,
|
|
SP_INTERNAL_ADAPTER_ERROR,
|
|
7 << 8
|
|
);
|
|
|
|
return(SP_RETURN_ERROR);
|
|
}
|
|
|
|
// Zero out noncachedExtension which contains the CoreGlobals.
|
|
for ( i = 0; i < sizeof(NONCACHED_EXTENSION); i++)
|
|
((PUCHAR)noncachedExtension)[i] = 0;
|
|
|
|
// Address of host adapter.
|
|
noncachedExtension->CoreGlobals.HAOrigPhysAddr = foundRomAddr;
|
|
|
|
// Address of ROM image.
|
|
noncachedExtension->CoreGlobals.HAPhysAddr = foundRomAddr;
|
|
|
|
// Get Virtual address space for the HBA ROM from basePtr pointer.
|
|
noncachedExtension->CoreGlobals.HAVirtAddr = (ULONG)basePtr;
|
|
|
|
noncachedExtension->CoreGlobals.GlobalPhysAddr =
|
|
ScsiPortConvertPhysicalAddressToUlong(
|
|
ScsiPortGetPhysicalAddress(
|
|
DeviceExtension,
|
|
NULL,
|
|
&DeviceExtension->NoncachedExtension->CoreGlobals,
|
|
&Length));
|
|
|
|
// CHIP_PHYS is the physical address of a memory mapped SCSI chip
|
|
// on the mother board. This value is in the ROM header of the
|
|
// CAMcore.
|
|
|
|
if ( gLong(basePtr,CHIP_PHYS) )
|
|
noncachedExtension->CoreGlobals.ChipVirtAddr =
|
|
noncachedExtension->CoreGlobals.HAVirtAddr + gLong(basePtr,CHIP_PHYS);
|
|
|
|
// CHIP_OFFSET is the offset from the beginning of the ROM for
|
|
// a memory mapped SCSI chip on an HBA. This is also in the
|
|
// ROM header of the CAMcore initialized from the .RSP file
|
|
// when the CAMcore is built.
|
|
|
|
else
|
|
noncachedExtension->CoreGlobals.ChipVirtAddr =
|
|
noncachedExtension->CoreGlobals.HAVirtAddr + gWord(basePtr,CHIP_OFFSET);
|
|
|
|
if ( gWord(basePtr,RAM_OFFSET) )
|
|
noncachedExtension->CoreGlobals.HARAMVirtAddr =
|
|
noncachedExtension->CoreGlobals.HAVirtAddr + gWord(basePtr,RAM_OFFSET);
|
|
|
|
ConfigInfo->NumberOfAccessRanges = 2;
|
|
|
|
// Initialize AccessRanges in the ConfigInfo data structure
|
|
// for the ROM CAMcore and the SCSI chip on HBA.
|
|
|
|
(*ConfigInfo->AccessRanges)[AccessRangeROMIndex].RangeStart =
|
|
ScsiPortConvertUlongToPhysicalAddress(
|
|
noncachedExtension->CoreGlobals.HAPhysAddr );
|
|
|
|
// Length of ROM in 3rd byte of ROMHeader.
|
|
|
|
(*ConfigInfo->AccessRanges)[AccessRangeROMIndex].RangeLength =
|
|
ROMHeader->ROMlen * 512;
|
|
|
|
(*ConfigInfo->AccessRanges)[AccessRangeROMIndex].RangeInMemory = TRUE;
|
|
|
|
// Initialize AccessRanges for Chip on HBA.
|
|
// Number of chip ports is set to 200 -- 53C720 is 92 bytes (0x5c).
|
|
|
|
(*ConfigInfo->AccessRanges)[AccessRangeChipIndex].RangeLength = 200;
|
|
|
|
// Check whether we are I/O mapped or memory mapped.
|
|
if ( noncachedExtension->CoreGlobals.BasePort )
|
|
{
|
|
// IO mapped SCSI chip.
|
|
(*ConfigInfo->AccessRanges)
|
|
[AccessRangeChipIndex].RangeInMemory = FALSE;
|
|
|
|
(*ConfigInfo->AccessRanges)[AccessRangeChipIndex].RangeStart =
|
|
ScsiPortConvertUlongToPhysicalAddress(
|
|
noncachedExtension->CoreGlobals.BasePort );
|
|
}
|
|
else
|
|
{
|
|
// Memory mapped SCSI chip
|
|
(*ConfigInfo->AccessRanges)
|
|
[AccessRangeChipIndex].RangeInMemory = TRUE;
|
|
|
|
if ( gLong(basePtr,CHIP_PHYS) )
|
|
(*ConfigInfo->AccessRanges)[AccessRangeChipIndex].RangeStart =
|
|
ScsiPortConvertUlongToPhysicalAddress(
|
|
noncachedExtension->CoreGlobals.HAPhysAddr + gLong(basePtr,CHIP_PHYS) );
|
|
else
|
|
(*ConfigInfo->AccessRanges)[AccessRangeChipIndex].RangeStart =
|
|
ScsiPortConvertUlongToPhysicalAddress(
|
|
noncachedExtension->CoreGlobals.HAPhysAddr + gWord(basePtr,CHIP_OFFSET) );
|
|
}
|
|
|
|
// Now extract information from the REX header
|
|
|
|
// Size of the 32-bit code.
|
|
|
|
fileSize = rp->sizeQuo * 512 + rp->sizeRem - 512;
|
|
fileSize -= rp->headSize * 16;
|
|
|
|
DebugPrint((1, "NCR SDMS: FindCore ...REX file size = %d \n", fileSize));
|
|
|
|
// Point "src" to beginning of the 32-bit code. Have to skip
|
|
// around the REX header information.
|
|
|
|
src = (char *)((long)rp + rp->headSize * 16);
|
|
|
|
// Copy the 32-bit code from the ROM into the Device Extension.
|
|
|
|
for ( i = 0; i < fileSize; i++ )
|
|
DeviceExtension->base32BitCode[i] = src[i];
|
|
|
|
// Perform relocation.
|
|
|
|
// Set "relocTable" to first item to be relocated.
|
|
|
|
relocTable = (ulong *)( (long)rp + rp->relocOffset );
|
|
|
|
// Relocate all items in relocation table. Insure that each
|
|
// item has the high bit set before relocation.
|
|
for ( i = 0; i < rp->numReloc; i++ )
|
|
{
|
|
// The high bit of the values in the relocation table is
|
|
// set if 32 bits wide so, it should be set since
|
|
// this is 32 bit code. If it is not set, free device
|
|
// extension and return to caller.
|
|
if ( (relocTable[i] & 0x80000000) == 0 )
|
|
{
|
|
ScsiPortFreeDeviceBase( DeviceExtension, basePtr );
|
|
return( SP_RETURN_ERROR );
|
|
}
|
|
itemPtr = (ulong *)(DeviceExtension->base32BitCode +
|
|
(relocTable[i] & 0x7fffffff));
|
|
|
|
*itemPtr += (long)DeviceExtension->base32BitCode;
|
|
}
|
|
|
|
// Setup pointer to relocated 32-bit code. Note, must use "src"
|
|
// rather than base32BitCode because relocation changes
|
|
// CAM32Header.
|
|
|
|
cp = (CAM32Header *)src;
|
|
|
|
// Pointer to CAMInit.
|
|
|
|
DeviceExtension->initPtr =
|
|
(PVOID)(DeviceExtension->base32BitCode +
|
|
cp->initOffset);
|
|
|
|
// Pointer to CAMStart.
|
|
|
|
DeviceExtension->startPtr =
|
|
(PVOID)(DeviceExtension->base32BitCode +
|
|
cp->startOffset);
|
|
|
|
// Pointer to CAMInterrupt.
|
|
|
|
DeviceExtension->interruptPtr =
|
|
(PVOID)(DeviceExtension->base32BitCode +
|
|
cp->interruptOffset);
|
|
|
|
// Pointer to chsMap.
|
|
|
|
DeviceExtension->chsPtr =
|
|
(PVOID)(DeviceExtension->base32BitCode +
|
|
cp->chsOffset);
|
|
|
|
// Increment HBA count.
|
|
hwInfo->hbaCount++;
|
|
|
|
return SP_RETURN_FOUND;
|
|
|
|
} // End FindCore
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// InitPath
|
|
//
|
|
// Initializes the CAMCore after it is found by FindCore.
|
|
// Sets up CAMCore globals.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
VOID
|
|
InitPath(
|
|
IN PHW_DEVICE_EXTENSION DeviceExtension
|
|
)
|
|
{
|
|
PNONCACHED_EXTENSION noncachedExtension = DeviceExtension->NoncachedExtension;
|
|
|
|
DebugPrint(( 1, "NCR SDMS: InitPath \n"));
|
|
|
|
noncachedExtension->CoreGlobals.CoreInitialized = 0;
|
|
|
|
// Call CAMInit. Delays for hardware to reset are in the CAMcore.
|
|
(*DeviceExtension->initPtr)(&noncachedExtension->CoreGlobals);
|
|
|
|
// Tell the port driver the bus has been reset.
|
|
ScsiPortNotification( ResetDetected, DeviceExtension, DeviceExtension->scsiBusId );
|
|
|
|
DebugPrint(( 1, "NCR SDMS: InitPath ...after CAMInit \n"));
|
|
|
|
} // End InitPath
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// NCRHwInitialize
|
|
//
|
|
// This routine is called by the OS specific port driver
|
|
// when the host bus adapter needs to be initialized
|
|
// after a boot or a power failure. This routine only
|
|
// needs to initialize the hardware host bus adapter
|
|
// but should avoid resetting the SCSI bus.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// DeviceExtension - supplies the HBA miniport driver's
|
|
// storage for adapter data.
|
|
//
|
|
// Returns TRUE or FALSE.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOLEAN
|
|
NCRHwInitialize(
|
|
IN PVOID HwDeviceExtension
|
|
)
|
|
{
|
|
PHW_DEVICE_EXTENSION DeviceExtension = HwDeviceExtension;
|
|
PNONCACHED_EXTENSION noncachedExtension = DeviceExtension->NoncachedExtension;
|
|
|
|
DebugPrint(( 1, "NCR SDMS: NCRHwInitialize \n"));
|
|
|
|
// Don't reset SCSI bus.
|
|
noncachedExtension->CoreGlobals.config_info |=
|
|
CORHDR_DO_NOT_RESET_SCSI_BUS;
|
|
|
|
// Call CAMInit in CAMcore to reset and initialize the SCSI chip
|
|
// and CoreGlobals. Delays for hardware to reset are in the CAMcore.
|
|
InitPath( DeviceExtension );
|
|
|
|
noncachedExtension->CoreGlobals.config_info &=
|
|
!(CORHDR_DO_NOT_RESET_SCSI_BUS);
|
|
|
|
DebugPrint(( 1, "NCR SDMS: NCRHwInitialize ...exiting\n"));
|
|
|
|
return TRUE;
|
|
|
|
} // End NCRHwInitialize
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// NCRResetBus
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOLEAN
|
|
NCRResetBus(
|
|
IN PVOID HwDeviceExtension,
|
|
IN ULONG PathId
|
|
)
|
|
{
|
|
PHW_DEVICE_EXTENSION DeviceExtension = HwDeviceExtension;
|
|
PNONCACHED_EXTENSION noncachedExtension = DeviceExtension->NoncachedExtension;
|
|
|
|
DebugPrint(( 1, "NCR SDMS: NCRResetBus \n" ));
|
|
|
|
// Calls CAMInit routine in CAMcore to Reset SCSI Bus
|
|
// and initialize CoreGlobals.
|
|
noncachedExtension->CoreGlobals.config_info &=
|
|
!(CORHDR_DO_NOT_RESET_SCSI_BUS);
|
|
|
|
|
|
DebugPrint(( 2, "NCR SDMS: NCRResetBus ...entering InitPath\n"));
|
|
|
|
// Call CAMInit. Delays for hardware to reset are in the CAMcore.
|
|
InitPath( DeviceExtension );
|
|
|
|
DebugPrint(( 2, "NCR SDMS: NCRResetBus ...after InitPath\n"));
|
|
|
|
// Complete all outstanding requests with SRB_STATUS_BUS_RESET
|
|
ScsiPortCompleteRequest( DeviceExtension,
|
|
(UCHAR)PathId,
|
|
0xFF,
|
|
0xFF,
|
|
SRB_STATUS_BUS_RESET );
|
|
|
|
DebugPrint(( 2, "NCR SDMS: NCRResetBus ...complete\n"));
|
|
|
|
return TRUE;
|
|
|
|
} // End NCRResetBus
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// NCRStartIo
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOLEAN
|
|
NCRStartIo(
|
|
IN PVOID HwDeviceExtension,
|
|
IN PSCSI_REQUEST_BLOCK Srb
|
|
)
|
|
{
|
|
PHW_DEVICE_EXTENSION DeviceExtension = HwDeviceExtension;
|
|
PNONCACHED_EXTENSION noncachedExtension = DeviceExtension->NoncachedExtension;
|
|
PROMscsiCCB pROMCcb = Srb->SrbExtension;
|
|
|
|
DebugPrint(( 1, "NCR SDMS: NCRStartIo \n"));
|
|
|
|
switch ( Srb->Function )
|
|
{
|
|
case SRB_FUNCTION_EXECUTE_SCSI:
|
|
|
|
// For SDMS V1.6, reject all LUNs except zero. The
|
|
// version cannot handle the LUNs.
|
|
if ( ( DeviceExtension->SdmsVersion == SDMS_V16 ) &&
|
|
( Srb->Lun != 0x00 ) )
|
|
{
|
|
Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
|
|
|
|
DebugPrint((3, "NCR SDMS: StartIO ...LUN %d aborted\n",
|
|
Srb->Lun ));
|
|
|
|
ScsiPortNotification( RequestComplete,
|
|
DeviceExtension,
|
|
Srb);
|
|
|
|
ScsiPortNotification( NextRequest,
|
|
DeviceExtension,
|
|
NULL);
|
|
return TRUE;
|
|
}
|
|
|
|
BuildCCBFromSRB( DeviceExtension, Srb );
|
|
|
|
// If BuildCCBFromSRB was unsuccessful, it will set the
|
|
// SRB Status field to indicate that the I/O request should
|
|
// be aborted.
|
|
if ( Srb->SrbStatus == SRB_STATUS_ABORTED)
|
|
{
|
|
DebugPrint(( 3, "NCR SDMS: StartIO ...abort request\n"));
|
|
|
|
ScsiPortNotification( RequestComplete,
|
|
DeviceExtension,
|
|
Srb);
|
|
|
|
ScsiPortNotification( NextRequest,
|
|
DeviceExtension,
|
|
NULL);
|
|
return TRUE;
|
|
}
|
|
|
|
DebugPrint(( 2, "NCR SDMS: StartIO ...call CAMStart \n"));
|
|
|
|
// Call CAMstart
|
|
( *DeviceExtension->startPtr )
|
|
( &noncachedExtension->CoreGlobals,
|
|
Srb->SrbExtension );
|
|
|
|
DebugPrint(( 2, "NCR SDMS: StartIO ...back from CAMStart \n"));
|
|
|
|
break;
|
|
|
|
case SRB_FUNCTION_ABORT_COMMAND:
|
|
|
|
DebugPrint(( 3, "NCR SDMS: NCRStartIo ...Abort command received \n"));
|
|
|
|
// Abort not supported --- once CAMstart is called with a valid
|
|
// CCB it can't be aborted unless a reset is done.
|
|
Srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
|
|
|
|
ScsiPortNotification( RequestComplete,
|
|
DeviceExtension,
|
|
Srb);
|
|
|
|
ScsiPortNotification( NextRequest,
|
|
DeviceExtension,
|
|
NULL);
|
|
return TRUE;
|
|
|
|
case SRB_FUNCTION_RESET_BUS:
|
|
|
|
if ( !NCRResetBus( DeviceExtension, Srb->PathId) )
|
|
{
|
|
|
|
DebugPrint(( 3, "NCR SDMS: NCRStartIo ...Reset Bus failed \n"));
|
|
|
|
Srb->SrbStatus = SRB_STATUS_ERROR;
|
|
}
|
|
else
|
|
Srb->SrbStatus = SRB_STATUS_SUCCESS;
|
|
|
|
ScsiPortNotification( RequestComplete,
|
|
DeviceExtension,
|
|
Srb);
|
|
|
|
ScsiPortNotification( NextRequest,
|
|
DeviceExtension,
|
|
NULL);
|
|
return TRUE;
|
|
|
|
case SRB_FUNCTION_RESET_DEVICE:
|
|
|
|
DebugPrint(( 3, "NCR SDMS: NCRStartIo ...Reset device not supported. \n"));
|
|
|
|
// Reset device not supported. drop through to default.
|
|
|
|
// Return bad function SRB status for unsupported functions.
|
|
default:
|
|
Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
|
|
ScsiPortNotification( RequestComplete,
|
|
DeviceExtension,
|
|
Srb);
|
|
|
|
ScsiPortNotification( NextRequest,
|
|
DeviceExtension,
|
|
NULL);
|
|
return TRUE;
|
|
break;
|
|
|
|
} // End switch
|
|
|
|
return TRUE;
|
|
|
|
} // End NCRStartIo
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// BuildCCBFromSRB
|
|
//
|
|
// Translates the NT I/O request data structure (Srb) into a
|
|
// SDMS CAMcore I/O data structure (CCB).
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
VOID
|
|
BuildCCBFromSRB(
|
|
IN PHW_DEVICE_EXTENSION DeviceExtension,
|
|
IN PSCSI_REQUEST_BLOCK Srb
|
|
)
|
|
{
|
|
|
|
PROMscsiCCB pROMCcb = Srb->SrbExtension;
|
|
ULONG i;
|
|
ULONG Length;
|
|
|
|
DebugPrint(( 1, "NCR SDMS: BuildCCBFromSRB \n"));
|
|
|
|
// Zero out the CCB storage area.
|
|
for ( i = 0; i < sizeof(ROMscsiCCB); i++)
|
|
((PUCHAR)pROMCcb)[i] = 0;
|
|
|
|
// Save the SRB address in the CCB
|
|
pROMCcb->SCSIReq.PeripheralPtr = (ULONG)Srb;
|
|
|
|
pROMCcb->SCSIReq.Header.CCBLength = sizeof( SCSIRequestCCB );
|
|
pROMCcb->SCSIReq.Header.FunctionCode = FUNC_EXECUTE_SCSI_IO;
|
|
pROMCcb->SCSIReq.Header.CAMStatus = STAT_REQUEST_IN_PROGRESS;
|
|
pROMCcb->SCSIReq.Header.SCSIStatus = 0;
|
|
pROMCcb->SCSIReq.Header.PathID = Srb->PathId;
|
|
|
|
if ( Srb->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE )
|
|
pROMCcb->SCSIReq.Header.CAMFlags |= CAM_QUEUE_ACTION_SPECIFIED;
|
|
|
|
if ( Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT )
|
|
pROMCcb->SCSIReq.Header.CAMFlags |= CAM_DO_NOT_ALLOW_DISCONNECT;
|
|
|
|
if ( Srb->SrbFlags & SRB_FLAGS_DISABLE_SYNCH_TRANSFER )
|
|
pROMCcb->SCSIReq.Header.CAMFlags |= CAM_DISABLE_SYNC_TRAN;
|
|
|
|
// Disable auto request sense
|
|
pROMCcb->SCSIReq.Header.CAMFlags |= CAM_DISABLE_AUTOSENSE;
|
|
|
|
// Don't check this now because we don't currently support autosense.
|
|
// if ( Srb->SrbFlags & SRB_FLAGS_DISABLE_AUTOSENSE )
|
|
// pROMCcb->SCSIReq.Header.CAMFlags |= CAM_DISABLE_AUTOSENSE;
|
|
|
|
if ( Srb->SrbFlags & SRB_FLAGS_DATA_IN )
|
|
pROMCcb->SCSIReq.Header.CAMFlags |= CAM_DIR_DATA_IN;
|
|
else if ( Srb->SrbFlags & SRB_FLAGS_DATA_OUT )
|
|
pROMCcb->SCSIReq.Header.CAMFlags |= CAM_DIR_DATA_OUT;
|
|
else
|
|
pROMCcb->SCSIReq.Header.CAMFlags |= CAM_DIR_NO_DATA;
|
|
|
|
// SRB_FLAGS not supported
|
|
//
|
|
// SRB_FLAGS_BYPASS_FROZEN_QUEUE 0x00000010
|
|
// SRB_FLAGS_NO_QUEUE_FREEZE 0x00000100
|
|
// SRB_FLAGS_ADAPTER_CACHE_ENABLE 0x00000200
|
|
// SRB_FLAGS_IS_ACTIVE 0x00010000
|
|
// SRB_FLAGS_ALLOCATED_FROM_ZONE 0x00020000
|
|
|
|
pROMCcb->SCSIReq.TargetID = Srb->TargetId;
|
|
pROMCcb->SCSIReq.LUN = Srb->Lun;
|
|
pROMCcb->SCSIReq.Queue_Action = Srb->QueueAction;
|
|
|
|
// Following field has no SRB equivalent.
|
|
// pROMCcb->SCSIReq.VendorFlags = xxx;
|
|
|
|
(UCHAR)pROMCcb->SCSIReq.CDBLength = Srb->CdbLength;
|
|
(UCHAR)pROMCcb->ROMFields.CDBLength = Srb->CdbLength;
|
|
(UCHAR)pROMCcb->SCSIReq.SenseLength = Srb->SenseInfoBufferLength;
|
|
|
|
// No SRB equivalent -- already set to zero.
|
|
// pROMCcb->SCSIReq.MessageLength = 0;
|
|
|
|
// Set Scatter/Gather list length to zero.
|
|
pROMCcb->SCSIReq.SGListLength = 0;
|
|
|
|
// Set data length to SRB data length.
|
|
pROMCcb->SCSIReq.DataLength = Srb->DataTransferLength;
|
|
|
|
pROMCcb->SCSIReq.TimeOut = Srb->TimeOutValue;
|
|
|
|
// Unique fields added to end of CAM CCB for CAMcore code.
|
|
// This is here probably because some core at some time
|
|
// under a specific operating system needed physical as
|
|
// well as virtual addresses.
|
|
// This should be removed from SDMS 3.0.
|
|
|
|
pROMCcb->SCSIReq.DataPtr = ScsiPortConvertPhysicalAddressToUlong(
|
|
ScsiPortGetPhysicalAddress( DeviceExtension,
|
|
Srb,
|
|
Srb->DataBuffer,
|
|
&Length));
|
|
|
|
// If available memory not enough for data buffer, set the
|
|
// Srb Status field to ABORT and NCRStartIo will handle
|
|
// aborting the request.
|
|
if ( Length < Srb->DataTransferLength )
|
|
{
|
|
DebugPrint(( 2, "NCR SDMS: BuildCCBFromSrb ...Phys buffer length < SRB->DataTransferLength \n" ));
|
|
DebugPrint(( 2, " Physical Buffer Length = 0x%lx\n",
|
|
Length));
|
|
DebugPrint(( 2, " SRB Data Transfer Length = 0x%lx\n",
|
|
Srb->DataTransferLength));
|
|
|
|
Srb->SrbStatus = SRB_STATUS_ABORTED;
|
|
|
|
return;
|
|
}
|
|
|
|
pROMCcb->ROMFields.DataPhys = pROMCcb->SCSIReq.DataPtr;
|
|
|
|
// Setup data buffer virtual address.
|
|
|
|
pROMCcb->ROMFields.DataVirt = (ULONG)Srb->DataBuffer;
|
|
|
|
// Since AutoSense is disabled, set the sense buffers to zero.
|
|
pROMCcb->SCSIReq.SensePtr = 0;
|
|
pROMCcb->ROMFields.SensePhys = 0;
|
|
|
|
// Setup virtual address of Sense buffer.
|
|
pROMCcb->ROMFields.SenseVirt = (ULONG)Srb->SenseInfoBuffer;
|
|
|
|
// Following fields have already been cleared when CCB zeroed.
|
|
// They have no SRB equivalent.
|
|
|
|
// pROMCcb->SCSIReq.MessagePtr = 0;
|
|
// pROMCcb->SCSIReq.LinkPtr = 0;
|
|
// pROMCcb->SCSIReq.PeripheralPtr = 0;
|
|
// pROMCcb->SCSIReq.CallBackPtr[0] = 0;
|
|
// pROMCcb->SCSIReq.CallBackPtr[1] = 0;
|
|
// pROMCcb->SCSIReq.CallBackPtr[2] = 0;
|
|
|
|
// Copy the SRB CDB to the CCB CDB (and ROMFields CCB)
|
|
for ( i=0; i<Srb->CdbLength; i++) {
|
|
pROMCcb->SCSIReq.CDB[i] = Srb->Cdb[i];
|
|
pROMCcb->ROMFields.CDB[i] = Srb->Cdb[i];
|
|
}
|
|
|
|
DebugPrint(( 2, "NCR SDMS: BuildCCBFromSRB ...return \n"));
|
|
|
|
} // End BuildCCBFromSRB
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// NCRInterrupt
|
|
//
|
|
// Return value:
|
|
// TRUE -- interrupt belonged to this HBA.
|
|
// FALSE -- interrupt did not belong to this HBA.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOLEAN
|
|
NCRInterrupt(
|
|
IN PVOID HwDeviceExtension
|
|
)
|
|
{
|
|
PHW_DEVICE_EXTENSION DeviceExtension = HwDeviceExtension;
|
|
PNONCACHED_EXTENSION noncachedExtension = DeviceExtension->NoncachedExtension;
|
|
|
|
ULONG returnValue; // Return value from CAMInterrupt
|
|
ULONG newReturnValue;
|
|
|
|
PSCSI_REQUEST_BLOCK Srb;
|
|
PSCSIRequestCCB pScsiRequestCcb;
|
|
|
|
// Leave the debug level at 3 in case we have to debug the
|
|
// NTLDR program.
|
|
DebugPrint(( 3, "NCR SDMS: NCRInterrupt \n"));
|
|
|
|
// Tell the Core that this was a true interrupt from NT.
|
|
noncachedExtension->CoreGlobals.GlobalFlags |= GLOBAL_FLAGS_TRUE_INT;
|
|
|
|
// Call CAMInterrupt
|
|
|
|
returnValue = ( *DeviceExtension->interruptPtr )(&noncachedExtension->CoreGlobals);
|
|
|
|
// Set the flag to tell the Core the driver is calling again
|
|
// for interrupt servicing.
|
|
noncachedExtension->CoreGlobals.GlobalFlags &= ~GLOBAL_FLAGS_TRUE_INT;
|
|
|
|
// Leave the debug level at 3 in case we have to debug the
|
|
// NTLDR program.
|
|
DebugPrint(( 3, "NCR SDMS: NCRInterrupt ...after CAMInterrupt\n"));
|
|
|
|
// If CAMInterrupt returns 0, interrupt was not ours. Signal
|
|
// this fact to NT. If CAMInterrupt returns any other value,
|
|
// the interrupt was ours.
|
|
if (returnValue == 0)
|
|
{
|
|
// Leave the debug level at 3 in case we have to debug
|
|
// the NTLDR program.
|
|
DebugPrint(( 3, "NCR SDMS: NCRInterrupt ...not our interrupt \n"));
|
|
return FALSE;
|
|
}
|
|
|
|
// Return value of "1" or "2" indicates the interrupt was ours, but
|
|
// no other action occurred (i.e. the CCB is still outstanding).
|
|
// Poll CAMInterrupt until the CCB is complete.
|
|
|
|
// Return value of "1" indicates the interrupt was ours, but we
|
|
// must wait for NT to call us again.
|
|
if( returnValue == 1 )
|
|
return TRUE;
|
|
|
|
// Save the original return value from CAMInterrupt.
|
|
newReturnValue = returnValue;
|
|
|
|
while ( newReturnValue >= 2 )
|
|
{
|
|
DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...return value >= 2 \n"));
|
|
newReturnValue = ( *DeviceExtension->interruptPtr )(&noncachedExtension->CoreGlobals);
|
|
|
|
// If return value is greater than "2", this is a pointer
|
|
// to our CCB.
|
|
if ( newReturnValue > 2 )
|
|
returnValue = newReturnValue;
|
|
}
|
|
|
|
// If return value greater than "2", we tell NT that the
|
|
// interrupt was ours and wait for NT to call us again.
|
|
// If the inner loop (above) returned a "1" or "2", then the
|
|
// orignal value will still be "2".
|
|
if( returnValue == 2 )
|
|
return TRUE;
|
|
|
|
// CAMInterrupt returns the CCB that was serviced.
|
|
pScsiRequestCcb = (PSCSIRequestCCB)returnValue;
|
|
|
|
// Get the SRB from the CCB.
|
|
Srb = (PSCSI_REQUEST_BLOCK)pScsiRequestCcb->PeripheralPtr;
|
|
|
|
// Translate the CAM Status Flag to a SRB Status Flag.
|
|
|
|
// Update SCSI status (only if it is equal to 0x02).
|
|
if ( (UCHAR)pScsiRequestCcb->Header.SCSIStatus == 0x02 )
|
|
Srb->ScsiStatus = (UCHAR)pScsiRequestCcb->Header.SCSIStatus;
|
|
|
|
// Print the Data Length information.
|
|
DebugPrint(( 3, "NCR SDMS: NCRInterrupt ...CCB Data Length = 0x%lx\n",
|
|
(ULONG)pScsiRequestCcb->DataLength));
|
|
|
|
DebugPrint(( 3, "NCR SDMS: NCRInterrupt ...SRB Data Length = 0x%lx\n",
|
|
(ULONG)Srb->DataTransferLength));
|
|
|
|
switch ( (UCHAR)pScsiRequestCcb->Header.CAMStatus )
|
|
{
|
|
|
|
case STAT_REQUEST_IN_PROGRESS:
|
|
Srb->SrbStatus = (UCHAR)SRB_STATUS_PENDING;
|
|
DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_PENDING\n"));
|
|
return TRUE; // Current SRB is not completed.
|
|
break;
|
|
|
|
case STAT_REQUEST_DONE_NO_ERROR:
|
|
|
|
// Update the data length -- SDMS 1.6 only. SDMS 3.0 uses
|
|
// a different data field for residual count. The CCB
|
|
// data length will be zero if all data transferred.
|
|
// If the value is non-zero, this is the number of bytes
|
|
// NOT transferred.
|
|
|
|
if ((ULONG)pScsiRequestCcb->DataLength > 0)
|
|
{
|
|
Srb->DataTransferLength = (ULONG)pScsiRequestCcb->DataLength;
|
|
Srb->SrbStatus = (UCHAR)SRB_STATUS_DATA_OVERRUN;
|
|
}
|
|
else
|
|
{
|
|
Srb->SrbStatus = (UCHAR)SRB_STATUS_SUCCESS;
|
|
DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_SUCCESS\n"));
|
|
}
|
|
|
|
DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...Adjusted SRB Data Length = 0x%x\n",
|
|
(ULONG)Srb->DataTransferLength));
|
|
break;
|
|
|
|
case STAT_ABORTED_BY_HOST:
|
|
Srb->SrbStatus = (UCHAR)SRB_STATUS_ABORTED;
|
|
DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_ABORTED\n"));
|
|
break;
|
|
|
|
case STAT_UNABLE_TO_ABORT:
|
|
Srb->SrbStatus = (UCHAR)SRB_STATUS_ABORT_FAILED;
|
|
DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_ABORT_FAILED\n"));
|
|
break;
|
|
|
|
case STAT_COMPLETE_WITH_ERROR:
|
|
Srb->SrbStatus = (UCHAR)SRB_STATUS_ERROR;
|
|
DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_ERROR\n"));
|
|
break;
|
|
|
|
// Ask for another SRB???
|
|
case STAT_CAM_BUSY:
|
|
Srb->SrbStatus = (UCHAR)SRB_STATUS_BUSY;
|
|
DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_BUSY\n"));
|
|
break;
|
|
|
|
case STAT_INVALID_REQUEST:
|
|
Srb->SrbStatus = (UCHAR)SRB_STATUS_INVALID_REQUEST;
|
|
DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_INVALID REQUEST\n"));
|
|
break;
|
|
|
|
case STAT_INVALID_PATH_ID:
|
|
Srb->SrbStatus = (UCHAR)SRB_STATUS_INVALID_PATH_ID;
|
|
DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_INVALID_PATH_ID\n"));
|
|
break;
|
|
|
|
case STAT_SCSI_DEVICE_NOT_INSTALLED:
|
|
Srb->SrbStatus = (UCHAR)SRB_STATUS_NO_DEVICE;
|
|
DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_NO_DEVICE\n"));
|
|
break;
|
|
|
|
case STAT_WAIT_FOR_TIMEOUT:
|
|
Srb->SrbStatus = (UCHAR)SRB_STATUS_TIMEOUT;
|
|
DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_TIMEOUT\n"));
|
|
break;
|
|
|
|
case STAT_SELECTION_TIMEOUT:
|
|
Srb->SrbStatus = (UCHAR)SRB_STATUS_SELECTION_TIMEOUT;
|
|
DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_SELECTION_TIMEOUT\n"));
|
|
break;
|
|
|
|
case STAT_COMMAND_TIMEOUT:
|
|
Srb->SrbStatus = (UCHAR)SRB_STATUS_COMMAND_TIMEOUT;
|
|
DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_COMMAND_TIMEOUT \n"));
|
|
break;
|
|
|
|
// Ask for another SRB ??
|
|
case STAT_SCSI_BUS_BUSY: // No equivalent SRB Flag
|
|
Srb->SrbStatus = (UCHAR)SRB_STATUS_BUSY;
|
|
DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_BUSY \n"));
|
|
return TRUE; // Current SRB not complete
|
|
break;
|
|
|
|
case STAT_MESSAGE_REJECT_RECIEVED:
|
|
Srb->SrbStatus = (UCHAR)SRB_STATUS_MESSAGE_REJECTED;
|
|
DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_MESSAGE_REJECTED \n"));
|
|
break;
|
|
|
|
case STAT_SCSI_BUS_RESET:
|
|
Srb->SrbStatus = (UCHAR)SRB_STATUS_BUS_RESET;
|
|
DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_BUS_RESET \n"));
|
|
// Notify port driver of SCSI Reset
|
|
ScsiPortNotification( ResetDetected,
|
|
DeviceExtension,
|
|
Srb->PathId);
|
|
return TRUE;
|
|
|
|
break;
|
|
|
|
case STAT_UNCORRECTED_PARITY_ERROR:
|
|
Srb->SrbStatus = (UCHAR)SRB_STATUS_PARITY_ERROR;
|
|
DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_PARITY_ERROR \n"));
|
|
break;
|
|
|
|
case STAT_REQUEST_SENSE_FAILED:
|
|
Srb->SrbStatus = (UCHAR)SRB_STATUS_REQUEST_SENSE_FAILED;
|
|
DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_SENSE_FAILED \n"));
|
|
break;
|
|
|
|
case STAT_NO_HBA_DETECTED_ERROR:
|
|
Srb->SrbStatus = (UCHAR)SRB_STATUS_NO_HBA;
|
|
DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_NO_HBA \n"));
|
|
break;
|
|
|
|
case STAT_DATA_OVERRUN_OR_UNDERRUN:
|
|
Srb->SrbStatus = (UCHAR)SRB_STATUS_DATA_OVERRUN;
|
|
DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_DATA_OVERRUN \n"));
|
|
break;
|
|
|
|
case STAT_UNEXPECTED_BUS_FREE:
|
|
Srb->SrbStatus = (UCHAR)SRB_STATUS_UNEXPECTED_BUS_FREE;
|
|
DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_UNEXPECTED_BUS_FREE \n"));
|
|
break;
|
|
|
|
case STAT_PHASE_SEQUENCE_FAILURE:
|
|
Srb->SrbStatus = (UCHAR)SRB_STATUS_PHASE_SEQUENCE_FAILURE;
|
|
DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_PHASE_SEQUENCE_FAILURE \n"));
|
|
break;
|
|
|
|
case STAT_CCB_LENGTH_INADEQUATE:
|
|
Srb->SrbStatus = (UCHAR)SRB_STATUS_BAD_SRB_BLOCK_LENGTH;
|
|
DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_BAD_SRB_BLOCK_LENGTH \n"));
|
|
break;
|
|
|
|
case STAT_CANNOT_PROVIDE_CAPABILITY: // No equivalent SRB Flag
|
|
Srb->SrbStatus = (UCHAR)SRB_STATUS_ERROR;
|
|
DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_ERROR \n"));
|
|
break;
|
|
|
|
case STAT_INVALID_LUN:
|
|
Srb->SrbStatus = (UCHAR)SRB_STATUS_INVALID_LUN;
|
|
DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_INVALID_LEN \n"));
|
|
break;
|
|
|
|
case STAT_INVALID_TARGET_ID:
|
|
Srb->SrbStatus = (UCHAR)SRB_STATUS_INVALID_TARGET_ID;
|
|
DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_INALID_TARGET_ID \n"));
|
|
break;
|
|
|
|
case STAT_FUNCTION_NOT_IMPLEMENTED:
|
|
Srb->SrbStatus = (UCHAR)SRB_STATUS_BAD_FUNCTION;
|
|
DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_BAD_FUNCTION \n"));
|
|
break;
|
|
|
|
// The following CAM Status flags have no SRB equivalent.
|
|
|
|
case STAT_NEXUS_NOT_ESTABLISHED:
|
|
case STAT_INVALID_INTIATOR_ID:
|
|
case STAT_INVALID_DATA_BUFFER:
|
|
case STAT_NO_CAM_PRESENT:
|
|
case STAT_GENERAL_FAILURE:
|
|
default:
|
|
Srb->SrbStatus = (UCHAR)SRB_STATUS_ERROR;
|
|
DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_ERROR \n"));
|
|
break;
|
|
|
|
} // End CAMStatus switch
|
|
|
|
// Notify the SCSI Port driver that this SRB is complete.
|
|
ScsiPortNotification( RequestComplete,
|
|
DeviceExtension,
|
|
Srb );
|
|
|
|
ScsiPortNotification( NextRequest,
|
|
DeviceExtension,
|
|
NULL );
|
|
|
|
// Indicate that the interrupt was ours.
|
|
return TRUE;
|
|
|
|
} // End NCRInterrupt
|
|
|
|
#else // not i386
|
|
|
|
ULONG
|
|
DriverEntry(
|
|
IN PVOID DriverObject,
|
|
IN PVOID Argument2
|
|
)
|
|
{
|
|
return SP_RETURN_NOT_FOUND;
|
|
} // DriverEntry
|
|
|
|
#endif // i386
|
|
|