diff options
Diffstat (limited to '')
-rw-r--r-- | private/ntos/miniport/spock/makefile | 6 | ||||
-rw-r--r-- | private/ntos/miniport/spock/mca.h | 245 | ||||
-rw-r--r-- | private/ntos/miniport/spock/sources | 36 | ||||
-rw-r--r-- | private/ntos/miniport/spock/spock.c | 2150 | ||||
-rw-r--r-- | private/ntos/miniport/spock/spock.rc | 12 |
5 files changed, 2449 insertions, 0 deletions
diff --git a/private/ntos/miniport/spock/makefile b/private/ntos/miniport/spock/makefile new file mode 100644 index 000000000..b4338519e --- /dev/null +++ b/private/ntos/miniport/spock/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT WINDOWS +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/ntos/miniport/spock/mca.h b/private/ntos/miniport/spock/mca.h new file mode 100644 index 000000000..77ceb4d2f --- /dev/null +++ b/private/ntos/miniport/spock/mca.h @@ -0,0 +1,245 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + mca.h + +Abstract: + + This is the include file for the IBM MCA SCSI adapter drivers. + +Author: + + Mike Glass (mglass) + +Notes: + +Revision History: + +--*/ + +#define MAXIMUM_SDL_SIZE 16 + +// +// Termination Status Block +// + +typedef struct _TSB { + USHORT ScbStatus; + USHORT Reserved; + ULONG ResidualByteCount; + PVOID SgDescriptorAddress; + USHORT DeviceStatusLength; + UCHAR DeviceStatus; + UCHAR CommandStatus; + UCHAR DeviceError; + UCHAR CommandError; + ULONG Reserved2; + PVOID ScbAddress; +} TSB, *PTSB; + +// +// TSB End Status +// + +#define TSB_STATUS_NO_ERROR 0x0000 +#define TSB_STATUS_SHORT_RECORD 0x0002 +#define TSB_STATUS_INVALID_COMMAND 0x0004 +#define TSB_STATUS_SCB_REJECTED 0x0008 +#define TSB_STATUS_SCB_SPECIFIC_CHECK 0x0010 +#define TSB_STATUS_LONG_RECORD 0x0020 +#define TSB_STATUS_SCB_HALTED 0x0040 +#define TSB_STATUS_SCB_INTERRUPT_QUEUED 0x0080 +#define TSB_STATUS_ADDITIONAL_STATUS 0x0100 +#define TSB_STATUS_DEVICE_STATUS 0x0200 +#define TSB_STATUS_DEVICE_NOT_INIT 0x0800 +#define TSB_STATUS_MAJOR_EXCEPTION 0x1000 + +// +// TSB Command Error Codes +// + +#define TSB_COMMAND_ERROR_DEVICE_NOT_ASSIGNED 0x0A + +// +// Scatter/Gather Descriptor and List +// + +typedef struct _SG_DESCRIPTOR { + ULONG Address; + ULONG Length; +} SG_DESCRIPTOR, *PSG_DESCRIPTOR; + +typedef struct _SDL { + SG_DESCRIPTOR Descriptor[MAXIMUM_SDL_SIZE]; +} SDL, *PSDL; + +// +// Subsystem Control Block +// + +typedef struct _SCB { + + USHORT Command; + USHORT EnableFlags; + USHORT CdbSize; + USHORT Reserved; + ULONG BufferAddress; + ULONG BufferLength; + ULONG StatusBlock; + struct _SCB *NextScb; + UCHAR Cdb[12]; + TSB Tsb; + SDL Sdl; + PVOID SrbAddress; + +} SCB, *PSCB; + +// +// SCB Commands +// + +#define SCB_COMMAND_ABORT 0x040F +#define SCB_COMMAND_ASSIGN 0x000E +#define SCB_COMMAND_INQUIRY 0x000B +#define SCB_COMMAND_DMA_CONTROL 0x000D +#define SCB_COMMAND_FEATURE_CONTROL 0x040C +#define SCB_COMMAND_FORMAT_PREPARE 0x0017 +#define SCB_COMMAND_FORMAT 0x0016 +#define SCB_COMMAND_GET_STATUS 0x0007 +#define SCB_COMMAND_GET_POS 0x1c0a +#define SCB_COMMAND_READ 0x0001 +#define SCB_COMMAND_READ_CAPACITY 0x1c09 +#define SCB_COMMAND_READ_VERIFY 0x0003 +#define SCB_COMMAND_REASSIGN_BLOCK 0x0018 +#define SCB_COMMAND_REQUEST_SENSE 0x0008 +#define SCB_COMMAND_RESET 0x0400 +#define SCB_COMMAND_SEND_SCSI 0x241F +#define SCB_COMMAND_WRITE 0x0002 +#define SCB_COMMAND_WRITE_VERIFY 0x0004 + +// +// SCB Command Masks +// + +#define SCB_NO_DISCONNECT 0x0080 +#define SCB_NO_SYNCHRONOUS_TRANSFER 0x0040 + +// +// SCB Enable Options Masks +// + +#define SCB_ENABLE_WRITE 0x0000 +#define SCB_ENABLE_READ 0x8000 +#define SCB_ENABLE_TSB_ON_ERROR 0x4000 +#define SCB_ENABLE_RETRY_ENABLE 0x2000 +#define SCB_ENABLE_SG_LIST 0x1000 +#define SCB_ENABLE_SHORT_TRANSFER 0x0400 +#define SCB_ENABLE_BYPASS_BUFFER 0x0200 +#define SCB_ENABLE_CHAINING 0x0100 + +// +// SCB Command Status +// + +#define SCB_STATUS_SUCCESS 0x01 +#define SCB_STATUS_SUCCESS_WITH_RETRIES 0x05 +#define SCB_STATUS_ADAPTER_FAILED 0x07 +#define SCB_STATUS_IMMEDIATE_COMMAND_COMPLETE 0x0A +#define SCB_STATUS_COMMAND_COMPLETE_WITH_FAILURE 0x0C +#define SCB_STATUS_COMMAND_ERROR 0x0E +#define SCB_STATUS_SOFTWARE_SEQUENCING_ERROR 0x0F + +// +// SCB Device Status +// + +#define SCB_DEV_STATUS_GOOD 0x00 +#define SCB_DEV_STATUS_CHECK_CONDITION 0x01 +#define SCB_DEV_STATUS_CONDITION_MET 0x02 +#define SCB_DEV_STATUS_BUSY 0x04 +#define SCB_DEV_STATUS_INTERMEDIATE_GOOD 0x08 +#define SCB_DEV_STATUS_INTERMEDIATE_CONDITION_MET 0x0A +#define SCB_DEV_STATUS_RESERVATION_CONFLICT 0x0C + +// +// MCA SCSI Adapter Registers +// + +typedef struct _MCA_REGISTERS { + ULONG CommandInterface; + UCHAR Attention; + UCHAR BaseControl; + UCHAR InterruptStatus; + UCHAR BasicStatus; +} MCA_REGISTERS, *PMCA_REGISTERS; + +// +// Attention Register Request Codes +// + +#define IMMEDIATE_COMMAND 0x10 +#define START_SCB 0x30 +#define START_LONG_SCB 0x40 +#define END_OF_INTERRUPT 0xE0 + +// +// Basic Control Register +// + +#define INTERRUPT_ENABLE 0x01 +#define DMA_ENABLE 0x02 +#define HARDWARE_RESET 0x80 + +// +// Basic Status Register +// + +#define BASIC_STATUS_BUSY 0x01 +#define BASIC_STATUS_INTERRUPT 0x02 +#define BASIC_STATUS_CI_EMPTY 0x04 +#define BASIC_STATUS_CI_FULL 0x08 + +#define MAXIMUM_DATA_TRANSFER (16 * 1024 * 1024) - 1 + +// +// Disk Activity Light Macros +// + +#define DISK_ACTIVITY_LIGHT_ON() { \ + UCHAR portContents; \ + portContents = ScsiPortReadPortUchar((PUCHAR)0x92); \ + portContents |= 0x40; \ + ScsiPortWritePortUchar((PUCHAR)0x92, portContents); \ +} + +#define DISK_ACTIVITY_LIGHT_OFF() { \ + UCHAR portContents; \ + portContents = ScsiPortReadPortUchar((PUCHAR)0x92); \ + portContents &= ~0x40; \ + ScsiPortWritePortUchar((PUCHAR)0x92, portContents); \ +} + +// +// POS and Adapter Information +// + +typedef struct _ADAPTER_INFORMATION { + USHORT AdapterId; + UCHAR PosRegister3; + UCHAR PosRegister2; + UCHAR PosRegister4; + UCHAR InterruptLevel; + USHORT RevisionLevel:12; + USHORT ChannelConnector:4; + UCHAR NumberOfDevicesSupported; + UCHAR NumberOfLogicalUnitsSupported; + UCHAR NumberOfLogicalDevicesSupported; + UCHAR DmaPacingFactor; + UCHAR MaximumAdapterBusyTime; + UCHAR EoiToInterruptOffTime; + USHORT Reserved; + USHORT DisableRetryDeviceBitMap; +} ADAPTER_INFORMATION, *PADAPTER_INFORMATION; diff --git a/private/ntos/miniport/spock/sources b/private/ntos/miniport/spock/sources new file mode 100644 index 000000000..48b03ea65 --- /dev/null +++ b/private/ntos/miniport/spock/sources @@ -0,0 +1,36 @@ +!IF 0 + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + sources. + +Abstract: + + This file specifies the target component being built and the list of + sources files needed to build that component. Also specifies optional + compiler switches and libraries that are unique for the component being + built. + + +Author: + + Steve Wood (stevewo) 12-Apr-1990 + +NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl + +!ENDIF + + +MAJORCOMP=ntos +MINORCOMP=miniport +TARGETNAME=spock + +TARGETPATH=\nt\public\sdk\lib +TARGETTYPE=MINIPORT +TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\scsiport.lib + +SOURCES=spock.c spock.rc + +INCLUDES=..\..\inc diff --git a/private/ntos/miniport/spock/spock.c b/private/ntos/miniport/spock/spock.c new file mode 100644 index 000000000..fbcad5932 --- /dev/null +++ b/private/ntos/miniport/spock/spock.c @@ -0,0 +1,2150 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + spock.c + +Abstract: + + This is the NT SCSI miniport driver for the IBM MCA SCSI adapter. + +Author: + + Mike Glass + +Environment: + + kernel mode only + +Notes: + +Revision History: + +--*/ +#include "miniport.h" +#include "mca.h" +#include "scsi.h" + +#define MAXIMUM_ERRORS 10 + +// +// The following table specifies the ports to be checked when searching for +// an adapter. A zero entry terminates the search. +// + +CONST ULONG AdapterAddresses[] = {0X3540, 0X3548, 0X3550, 0X3558, + 0X3560, 0X3568, 0x3570, 0x3578, 0}; + +// +// Device extension +// + +typedef struct _HW_DEVICE_EXTENSION { + + // + // Adapter parameters + // + + PMCA_REGISTERS Registers; + + // + // Disk activity light count + // + + ULONG ActiveRequests; + + ULONG ErrorCount; + + UCHAR HostTargetId; + +} HW_DEVICE_EXTENSION, *PHW_DEVICE_EXTENSION; + +// +// Logical unit extension +// + +typedef struct _HW_LOGICAL_UNIT { + + PSCB Scb; + PSCSI_REQUEST_BLOCK AbortSrb; + PSCSI_REQUEST_BLOCK CurrentSrb; + +} HW_LOGICAL_UNIT, *PHW_LOGICAL_UNIT; + +// +// Noncached version extension. +// + +typedef struct _HW_ADAPTER_INFOMATION { + SCB Scb; + ADAPTER_INFORMATION AdapterInfo; +}HW_ADAPTER_INFOMATION, *PHW_ADAPTER_INFOMATION; + + +// +// Function declarations +// + +ULONG +DriverEntry ( + IN PVOID DriverObject, + IN PVOID Argument2 + ); + +ULONG +SpockConfiguration( + IN PVOID HwDeviceExtension, + IN PVOID Context, + IN PVOID BusInformation, + IN PCHAR ArgumentString, + IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo, + OUT PBOOLEAN Again + ); + +BOOLEAN +SpockInitialize( + IN PVOID HwDeviceExtension + ); + +BOOLEAN +SpockStartIo( + IN PVOID HwDeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb + ); + +BOOLEAN +SpockInterrupt( + IN PVOID HwDeviceExtension + ); + +BOOLEAN +SpockResetBus( + IN PVOID HwDeviceExtension, + IN ULONG PathId + ); + +BOOLEAN +SpockAbortIo( + IN PVOID HwDeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb + ); + +VOID +BuildScb( + IN PHW_DEVICE_EXTENSION HwDeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb + ); + +VOID +BuildSgl( + IN PVOID DeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb + ); + +VOID +BuildReadCapacity( + IN PHW_DEVICE_EXTENSION DeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb + ); + +ULONG +McaAdapterPresent( + IN PHW_DEVICE_EXTENSION HwDeviceExtension, + IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo, + IN OUT PULONG AdapterCount, + OUT PBOOLEAN Again + ); + +VOID +MapTsbError( + IN PHW_DEVICE_EXTENSION DeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb, + IN PTSB Tsb + ); + +BOOLEAN +IssueScbCommand( + IN PVOID DeviceExtension, + IN ULONG PhysicalScb, + IN UCHAR TargetId + ); + +BOOLEAN +IssueImmediateCommand( + IN PVOID HwDeviceExtension, + IN ULONG ImmediateCommand, + IN UCHAR TargetId + ); + + +// +// Routines start +// + +ULONG +DriverEntry ( + IN PVOID DriverObject, + IN PVOID Argument2 + ) + +/*++ + +Routine Description: + + Installable driver initialization entry point for system. + +Arguments: + + Driver Object is passed to ScsiPortInitialize() + +Return Value: + + Status from ScsiPortInitialize() + +--*/ + +{ + HW_INITIALIZATION_DATA hwInitializationData; + ULONG adapterCount; + ULONG i; + + DebugPrint((1,"\n\nMCA SCSI Driver\n")); + + // + // Zero out structure. + // + + for (i=0; i<sizeof(HW_INITIALIZATION_DATA); i++) { + ((PUCHAR)&hwInitializationData)[i] = 0; + } + + // + // Set size of hwInitializationData. + // + + hwInitializationData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA); + + // + // Set entry points. + // + + hwInitializationData.HwInitialize = SpockInitialize; + hwInitializationData.HwFindAdapter = SpockConfiguration; + hwInitializationData.HwStartIo = SpockStartIo; + hwInitializationData.HwInterrupt = SpockInterrupt; + hwInitializationData.HwResetBus = SpockResetBus; + + hwInitializationData.DeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION); + hwInitializationData.SpecificLuExtensionSize = sizeof(HW_LOGICAL_UNIT); + + // + // Set number of access ranges and bus type.. + // + + hwInitializationData.NumberOfAccessRanges = 1; + hwInitializationData.AdapterInterfaceType = MicroChannel; + + // + // Indicate no buffer mapping but will need physical addresses. + // + + hwInitializationData.NeedPhysicalAddresses = TRUE; + + // + // Ask for SRB extensions for SCBs. + // + + hwInitializationData.SrbExtensionSize = sizeof(SCB); + + // + // The adapter count is used by McaAdapterPresent routine to track + // which adapter addresses have been searched. + // + + adapterCount = 0; + + return ScsiPortInitialize(DriverObject, + Argument2, + &hwInitializationData, + &adapterCount); + +} // end DriverEntry() + + +ULONG +SpockConfiguration( + IN PVOID HwDeviceExtension, + IN PVOID Context, + IN PVOID BusInformation, + IN PCHAR ArgumentString, + IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo, + OUT PBOOLEAN Again + ) + +/*++ + +Routine Description: + + Called from ScsiPortInitialize to collect adapter configuration + and capability information. + +Arguments: + + HwDevice Extension + Context - Pointer to adapters initialized count + BusInformation + ArgumentString - Not used + ConfigInfo - Configuration information structure describing HBA + Again - Indicates init routine should be called again + +Return Value: + + ULONG + +--*/ + +{ + PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; + PHW_ADAPTER_INFOMATION adapterInfo; + ULONG physicalAdapterInfo; + ULONG status; + UCHAR basicStatus; + + // + // Assume initialization will not need to be called again. + // + + *Again = FALSE; + + // + // Search for IBM SCSI adapters. + // + + status = McaAdapterPresent(HwDeviceExtension, + ConfigInfo, + Context, + Again); + + // + // If there are not adapter's found then return. + // + + if (status != SP_RETURN_FOUND) { + return(status); + } + + // + // Set IRQ to 14. + // + + ConfigInfo->BusInterruptLevel = 14; + ConfigInfo->NumberOfBuses = 1; + ConfigInfo->InterruptMode = LevelSensitive; + ConfigInfo->InitiatorBusId[0] = 7; + deviceExtension->HostTargetId = 7; + ConfigInfo->Master = TRUE; + ConfigInfo->ScatterGather = TRUE; + + // + // Indicate maximum transfer length is 16M. + // + + ConfigInfo->MaximumTransferLength = MAXIMUM_DATA_TRANSFER; + + // + // Maximum number of physical segments is 16. + // + + ConfigInfo->NumberOfPhysicalBreaks = MAXIMUM_SDL_SIZE; + + // + // Get an noncached extension for the adapter information. + // + + adapterInfo = ScsiPortGetUncachedExtension(HwDeviceExtension, + ConfigInfo, + sizeof(HW_ADAPTER_INFOMATION)); + + if (adapterInfo == NULL) { + return SP_RETURN_BAD_CONFIG; + } + + physicalAdapterInfo = ScsiPortConvertPhysicalAddressToUlong( + ScsiPortGetPhysicalAddress( + HwDeviceExtension, + NULL, + adapterInfo, + &status)); + + if (status == 0 || physicalAdapterInfo == SP_UNINITIALIZED_VALUE) { + return SP_RETURN_BAD_CONFIG; + } + + // + // Disable the adapter interrupt. The interrupts will be enabled + // when the adapter is initialized. + // + + basicStatus = ScsiPortReadPortUchar( + &deviceExtension->Registers->BaseControl); + + basicStatus &= ~INTERRUPT_ENABLE; + + ScsiPortWritePortUchar(&deviceExtension->Registers->BaseControl, basicStatus); + + // + // Build a get POS and adapter information command. + // + + adapterInfo->Scb.Command = SCB_COMMAND_GET_POS; + adapterInfo->Scb.EnableFlags = SCB_ENABLE_READ | SCB_ENABLE_TSB_ON_ERROR | + SCB_ENABLE_RETRY_ENABLE | SCB_ENABLE_BYPASS_BUFFER; + adapterInfo->Scb.CdbSize = 0; + adapterInfo->Scb.Reserved = 0; + adapterInfo->Scb.BufferAddress = physicalAdapterInfo + + offsetof(HW_ADAPTER_INFOMATION, AdapterInfo); + adapterInfo->Scb.BufferLength = sizeof(adapterInfo->AdapterInfo); + adapterInfo->Scb.StatusBlock = physicalAdapterInfo + + offsetof(HW_ADAPTER_INFOMATION, Scb.Tsb); + adapterInfo->Scb.NextScb = NULL; + + if (!IssueScbCommand(HwDeviceExtension, physicalAdapterInfo, 0x0f)) { + + DebugPrint((1, "SpockConfiguration: Could not issue get POS command.\n")); + + // + // Assume this is a bad adapter. Force no disconnects for all + // requests. + // + + deviceExtension->ErrorCount = MAXIMUM_ERRORS + 1; + + return SP_RETURN_FOUND; + } + + // + // Wait for the request to complete. + // + + for (status = 0; status < 1000; status++) { + + basicStatus = ScsiPortReadPortUchar(&deviceExtension->Registers->BasicStatus); + + if (basicStatus & BASIC_STATUS_INTERRUPT) { + break; + } + + ScsiPortStallExecution(10); + } + + + if (!(--deviceExtension->ActiveRequests)) { + + // + // Turn disk activity light off. + // + + DISK_ACTIVITY_LIGHT_OFF(); + } + + if (!(basicStatus & BASIC_STATUS_INTERRUPT)) { + + DebugPrint((1, "SpockConfiguration: Get POS command timed out.\n")); + + // + // Assume this is a bad adapter. Force no disconnects for all + // requests. + // + + deviceExtension->ErrorCount = MAXIMUM_ERRORS + 1; + return SP_RETURN_FOUND; + + } + + // + // Read interrupt status register to determine + // interrupting device and status. + // + + basicStatus = ScsiPortReadPortUchar( + &deviceExtension->Registers->InterruptStatus); + + // + // Acknowledge interrupt. + // + + status = 0; + while (ScsiPortReadPortUchar(&deviceExtension->Registers->BasicStatus) & + BASIC_STATUS_BUSY){ + + ScsiPortStallExecution(1); + + if (status++ > 10000) { + + DebugPrint((1, "SpockConfiguration: Wait for non-busy timed out.\n")); + + // + // Assume this is a bad adapter. Force no disconnects for all + // requests. + // + + deviceExtension->ErrorCount = MAXIMUM_ERRORS + 1; + return SP_RETURN_FOUND; + + } + } + + ScsiPortWritePortUchar(&deviceExtension->Registers->Attention, + (0x0f | END_OF_INTERRUPT)); + + // + // Bits 4-7 are interrupt status id. + // + + status = basicStatus >> 4; + + if (status != SCB_STATUS_SUCCESS && + status != SCB_STATUS_SUCCESS_WITH_RETRIES) { + + DebugPrint((1, "SpockConfiguration: Get POS command failed. Status = %hx\n", status)); + + // + // Assume this is a bad adapter. Force no disconnects for all + // requests. + // + + deviceExtension->ErrorCount = MAXIMUM_ERRORS + 1; + return SP_RETURN_FOUND; + + } + + DebugPrint((1, "SpockConfiguration: Retrived data is: %0.4hx\n",adapterInfo->AdapterInfo.RevisionLevel)); + + if (adapterInfo->AdapterInfo.RevisionLevel == 0xf) { + + DebugPrint((1, "SpockConfiguration: Found old firmware disabling disconnect!\n")); + deviceExtension->ErrorCount = MAXIMUM_ERRORS + 1; + + // + // Log nasty firmware. + // + + ScsiPortLogError( + HwDeviceExtension, + NULL, + 0, + deviceExtension->HostTargetId, + 0, + SP_BAD_FW_WARNING, + (10 << 16)); + } + + return SP_RETURN_FOUND; + +} // end SpockConfiguration() + + +BOOLEAN +SpockInitialize( + IN PVOID HwDeviceExtension + ) + +/*++ + +Routine Description: + + Reset and inititialize Adapter. + +Arguments: + + DeviceExtension - Adapter object device extension. + +Return Value: + + TRUE + +--*/ + +{ + PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; + UCHAR basicStatus; + + // + // Issue feature control immediate command to disable + // adapter timing of SCBs. + // + + if (!IssueImmediateCommand(HwDeviceExtension, + (ULONG)SCB_COMMAND_FEATURE_CONTROL, + 0x0f)) { + + DebugPrint((1,"SpockInitialize: Set feature control failed\n")); + } + + // + // Enable the adapter interrupt. + // + + basicStatus = ScsiPortReadPortUchar(&deviceExtension->Registers->BaseControl); + + basicStatus |= INTERRUPT_ENABLE; + + ScsiPortWritePortUchar(&deviceExtension->Registers->BaseControl, basicStatus); + + return TRUE; + +} // end SpockInitialize() + +BOOLEAN +SpockStartIo( + IN PVOID HwDeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb + ) + +/*++ + +Routine Description: + + Issue call to build SCB and SDL and write address and + command to adapter. + +Arguments: + + HwDeviceExtension + Srb + +Return Value: + + TRUE. + +--*/ + +{ + PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; + PSCB scb; + ULONG physicalScb; + ULONG length; + PHW_LOGICAL_UNIT logicalUnit; + + // + // Make sure that the request is for a valid SCSI bus and LUN as + // the IBM SCSI card does random things if address is wrong. + // + + if (Srb->PathId != 0 || Srb->Lun != 0) { + + // + // The spock card only supports logical unit zero and one bus. + // + + Srb->SrbStatus = SRB_STATUS_INVALID_LUN; + ScsiPortNotification(RequestComplete, + deviceExtension, + Srb); + // + // Adapter ready for next request. + // + + ScsiPortNotification(NextRequest, + deviceExtension, + NULL); + + return TRUE; + } + + // + // Get logical unit extension. + // + + logicalUnit = ScsiPortGetLogicalUnit(HwDeviceExtension, + Srb->PathId, + Srb->TargetId, + Srb->Lun); + + switch (Srb->Function) { + + case SRB_FUNCTION_EXECUTE_SCSI: + + // + // Save SRB in logical unit extension. + // + + ASSERT(!logicalUnit->CurrentSrb); + logicalUnit->CurrentSrb = Srb; + + scb = Srb->SrbExtension; + + // + // Save SRB back pointer in SCB. + // + + scb->SrbAddress = Srb; + + // + // Get SCB physical address. + // + + physicalScb = + ScsiPortConvertPhysicalAddressToUlong( + ScsiPortGetPhysicalAddress(deviceExtension, NULL, scb, &length)); + + // + // Assume physical address is contiguous for size of SCB. + // + + ASSERT(length >= sizeof(SCB)); + + // + // Save Scb in logical unit extension. + // + + logicalUnit->Scb = scb; + + // + // Build SCB. + // + + BuildScb(deviceExtension, Srb); + + // + // Issue send SCB command to adapter. + // + + DebugPrint((2, "BuildSCB: Function %0.4hx LDN %0.4hx \n", + Srb->Cdb[0], Srb->TargetId)); + + if (!IssueScbCommand(deviceExtension, + physicalScb, + Srb->TargetId)) { + + // + // Fail SRB. + // + + DebugPrint((1, "SpockStartIo: IssueScbCommand failed\n")); + + Srb->SrbStatus = SRB_STATUS_TIMEOUT; + + logicalUnit->CurrentSrb = NULL; + + ScsiPortNotification(RequestComplete, + deviceExtension, + Srb); + } + + break; + + case SRB_FUNCTION_ABORT_COMMAND: + + DebugPrint((3,"SpockStartIo: Abort command\n")); + + // + // Check to see if SRB to abort is still around. + // + + if (!logicalUnit->CurrentSrb) { + + // + // Request must of already completed. + // + + DebugPrint((1,"SpockStartIo: Srb to abort already complete\n")); + + // + // Complete ABORT SRB. + // + + Srb->SrbStatus = SRB_STATUS_ERROR; + + ScsiPortNotification(RequestComplete, + deviceExtension, + Srb); + + } else if (!SpockAbortIo(deviceExtension, Srb)) { + + DebugPrint((1,"SpockStartIo: Abort command failed\n")); + + Srb->SrbStatus = SRB_STATUS_ERROR; + + ScsiPortNotification(RequestComplete, + deviceExtension, + Srb); + } + + break; + + default: + + // + // Set error, complete request + // and signal ready for next request. + // + + DebugPrint((1,"SpockStartIo: Invalid SRB request\n")); + + Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST; + + ScsiPortNotification(RequestComplete, + deviceExtension, + Srb); + + } // end switch + + // + // Adapter ready for next request. + // + + ScsiPortNotification(NextRequest, + deviceExtension, + NULL); + + return TRUE; + +} // end SpockStartIo() + + +BOOLEAN +SpockInterrupt( + IN PVOID HwDeviceExtension + ) + +/*++ + +Routine Description: + + This is the interrupt handler for the IBM MCA SCSI adapter. + +Arguments: + + Device Object + +Return Value: + + Returns TRUE if interrupt expected. + +--*/ + +{ + PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; + PSCB scb; + PSCSI_REQUEST_BLOCK srb; + UCHAR srbStatus; + UCHAR scsiStatus; + PTSB tsb; + UCHAR status; + UCHAR targetId; + PHW_LOGICAL_UNIT logicalUnit; + ULONG logError = 0; + BOOLEAN srbValid = TRUE; + ULONG j; + + if (!(ScsiPortReadPortUchar(&deviceExtension->Registers->BasicStatus) & + BASIC_STATUS_INTERRUPT)) { + + // + // Spurious interrupt. + // + + return FALSE; + } + + // + // Read interrupt status register to determine + // interrupting device and status. + // + + status = ScsiPortReadPortUchar(&deviceExtension->Registers->InterruptStatus); + + // + // Bits 0-3 are device id and + // bits 4-7 are interrupt id. + // + + targetId = status & 0x0F; + status = status >> 4; + + // + // Acknowledge interrupt. + // + + j = 0; + while (ScsiPortReadPortUchar(&deviceExtension->Registers->BasicStatus) & + BASIC_STATUS_BUSY){ + + ScsiPortStallExecution(1); + + if (j++ > 10000) { + + ScsiPortLogError( + HwDeviceExtension, + NULL, + 0, + deviceExtension->HostTargetId, + 0, + SP_INTERNAL_ADAPTER_ERROR, + (9 << 16) | status + ); + + } + } + + ScsiPortWritePortUchar(&deviceExtension->Registers->Attention, + (UCHAR)(targetId | END_OF_INTERRUPT)); + + switch (status) { + + case SCB_STATUS_SUCCESS_WITH_RETRIES: + case SCB_STATUS_SUCCESS: + + srbStatus = SRB_STATUS_SUCCESS; + scsiStatus = SCSISTAT_GOOD; + DebugPrint((2, "Interupt Success: %0.4hx \n", + targetId)); + + break; + + case SCB_STATUS_IMMEDIATE_COMMAND_COMPLETE: + + if ((targetId & 7) != 7) { + + DebugPrint((1, "SpockInterrupt: Abort command complete\n")); + + // + // This is an ABORT command completion. + // + + + logicalUnit = ScsiPortGetLogicalUnit(HwDeviceExtension, + 0, + targetId, + 0); + + if (logicalUnit == NULL) { + break; + } + + if (logicalUnit->AbortSrb == NULL) { + logicalUnit = NULL; + break; + } + + // + // Get the SRB aborted. + // + + srb = logicalUnit->AbortSrb->NextSrb; + + srb->SrbStatus = SRB_STATUS_TIMEOUT; + + // + // Remove the aborted SRB from the logical unit. + // + + logicalUnit->CurrentSrb = NULL; + logicalUnit->Scb = NULL; + + // + // Call notification routine for the SRB. + // + + ScsiPortNotification(RequestComplete, + (PVOID)deviceExtension, + srb); + + // + // Complete the ABORT SRB. + // + + logicalUnit->AbortSrb->SrbStatus = SRB_STATUS_SUCCESS; + + ScsiPortNotification(RequestComplete, + (PVOID)deviceExtension, + logicalUnit->AbortSrb); + + } else { + + DebugPrint((1,"SpockInterrupt: Immediate command complete\n")); + } + + return TRUE; + + case SCB_STATUS_ADAPTER_FAILED: + case SCB_STATUS_COMMAND_ERROR: + case SCB_STATUS_SOFTWARE_SEQUENCING_ERROR: + + logError = SP_INTERNAL_ADAPTER_ERROR; + + case SCB_STATUS_COMMAND_COMPLETE_WITH_FAILURE: + + DebugPrint((2, "SpockInterrupt: Error\n")); + + srbStatus = SRB_STATUS_ERROR; + + break; + + default: + + srbValid = FALSE; + logError = SP_INTERNAL_ADAPTER_ERROR; + return TRUE; + + } // end switch() + + if (srbValid) { + + // + // Get SCB address from logical unit extension. + // + + logicalUnit = ScsiPortGetLogicalUnit(HwDeviceExtension, + 0, + targetId, + 0); + + if (logicalUnit == NULL || logicalUnit->Scb == NULL) { + + ScsiPortLogError( + HwDeviceExtension, + NULL, + 0, + deviceExtension->HostTargetId, + 0, + SP_INTERNAL_ADAPTER_ERROR, + (6 << 16) | status + ); + + return TRUE; + } + + scb = logicalUnit->Scb; + logicalUnit->Scb = NULL; + } + + if (logError != 0 ) { + + deviceExtension->ErrorCount++; + + // + // Log the error. + // + + ScsiPortLogError( + HwDeviceExtension, + NULL, + 0, + deviceExtension->HostTargetId, + 0, + SP_INTERNAL_ADAPTER_ERROR, + 1 << 16 | status + ); + + if (!srbValid) { + + // + // If the srb is not valid for this type of interrupt the + // return. + // + + return TRUE; + } + } + + // + // Get virtual TSB address. + // + + tsb = ScsiPortGetVirtualAddress(deviceExtension, ScsiPortConvertUlongToPhysicalAddress(scb->StatusBlock)); + + if (tsb == NULL) { + + deviceExtension->ErrorCount++; + + ScsiPortLogError( + HwDeviceExtension, + NULL, + 0, + deviceExtension->HostTargetId, + 0, + SP_INTERNAL_ADAPTER_ERROR, + (5 << 16) | status + ); + + return TRUE; + } + + // + // Get SRB and update status. + // + + srb = scb->SrbAddress; + + if (status == SCB_STATUS_COMMAND_COMPLETE_WITH_FAILURE) { + + // + // Get statuses from TSB. + // + + MapTsbError(deviceExtension, srb, tsb); + + } else { + + srb->SrbStatus = srbStatus; + srb->ScsiStatus = scsiStatus; + } + + // + // Remove the SRB from the logical unit extension. + // + + logicalUnit->CurrentSrb = NULL; + + // + // Call notification routine for the SRB. + // + + ScsiPortNotification(RequestComplete, + (PVOID)deviceExtension, + srb); + + if (!(--deviceExtension->ActiveRequests)) { + + // + // Turn disk activity light off. + // + + DISK_ACTIVITY_LIGHT_OFF(); + } + + return TRUE; + +} // end SpockInterrupt() + +BOOLEAN +SpockResetBus( + IN PVOID HwDeviceExtension, + IN ULONG PathId + ) + +/*++ + +Routine Description: + + Reset adapter and SCSI bus. + +Arguments: + + DeviceExtension + Pathid - identifies which bus on adapter that supports multiple + SCSI buses. + +Return Value: + + TRUE if reset completed + +--*/ + +{ + PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; + PMCA_REGISTERS mcaRegisters = deviceExtension->Registers; + ULONG i; + + UNREFERENCED_PARAMETER(PathId); + + deviceExtension->ErrorCount++; + + // + // Issue RESET command. + // + + if (!IssueImmediateCommand(HwDeviceExtension, + (ULONG)SCB_COMMAND_RESET, + 0x0f)) { + + DebugPrint((1,"SpockResetBus: Reset failed\n")); + return FALSE; + } + + // + // Wait 2 seconds for bus to quiet down. + // + + for (i=0; i<10; i++) { + + // + // Stall 200 milliseconds. + // + + ScsiPortStallExecution(200 * 1000); + } + + // + // Wait up to 3 more seconds for adapter to become ready. + // + + for (i=0; i<100; i++) { + + // + // Stall 3 milliseconds. + // + + ScsiPortStallExecution(30 * 1000); + + // + // If busy bit is set then reset adapter has not completed. + // + + if (ScsiPortReadPortUchar( + &mcaRegisters->BasicStatus) & BASIC_STATUS_BUSY) { + + continue; + + } else { + + break; + } + } + + if (i == 100) { + + DebugPrint((1,"SpockResetBus: Reset failed\n")); + ScsiPortLogError( + deviceExtension, + NULL, + 0, + deviceExtension->HostTargetId, + 0, + SP_INTERNAL_ADAPTER_ERROR, + 7 << 16 + ); + + return FALSE; + } + + // + // Issue feature control immediate command to disable + // adapter timing of SCBs. + // + + if (!IssueImmediateCommand(HwDeviceExtension, + (ULONG)SCB_COMMAND_FEATURE_CONTROL, + 0x0f)) { + + DebugPrint((1,"SpockResetBus: Set feature controls failed\n")); + } + + // + // Complete all outstanding requests with SRB_STATUS_BUS_RESET. + // + + ScsiPortCompleteRequest(deviceExtension, + (UCHAR)PathId, + 0xFF, + 0xFF, + (ULONG)SRB_STATUS_BUS_RESET); + + // + // Turn disk activity light off. + // + + DISK_ACTIVITY_LIGHT_OFF(); + + deviceExtension->ActiveRequests = 0; + + return TRUE; + +} // end SpockResetBus() + + +BOOLEAN +SpockAbortIo( + IN PVOID HwDeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb + ) + +/*++ + +Routine Description: + + Abort command in progress. + +Arguments: + + DeviceExtension + SRB + +Return Value: + + True, if command aborted. + +--*/ + +{ + PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; + PMCA_REGISTERS mcaRegisters = deviceExtension->Registers; + PHW_LOGICAL_UNIT logicalUnit; + ULONG i; + + // + // Wait up to 10 milliseconds until adapter is not busy. + // + + for (i=0; i<1000; i++) { + + if (ScsiPortReadPortUchar( + &mcaRegisters->BasicStatus) & BASIC_STATUS_BUSY) { + + // + // Wait 10 microseconds. + // + + ScsiPortStallExecution(10); + + } else { + + // + // Busy bit clear. Exit loop. + // + + break; + } + } + + if (i < 1000) { + + // + // Save SRB in logical unit extension. + // + + logicalUnit = ScsiPortGetLogicalUnit(HwDeviceExtension, + Srb->PathId, + Srb->TargetId, + Srb->Lun); + + logicalUnit->AbortSrb = Srb; + + // + // Issue abort to the command interface register. + // + + ScsiPortWritePortUlong(&mcaRegisters->CommandInterface, SCB_COMMAND_ABORT); + + // + // Write immediate command code to attention register. + // + + ScsiPortWritePortUchar(&mcaRegisters->Attention, (UCHAR)(Srb->TargetId | IMMEDIATE_COMMAND)); + + return TRUE; + + } else { + + // + // Timed out waiting for adapter to be in state to accept + // immediate command. Return TRUE so that the abort command + // will appear to have been sent and will time out causing a + // SCSI bus reset to occur. + + DebugPrint((1,"SpockAbortIo: Timed out waiting on BUSY adapter\n")); + + ScsiPortLogError( + deviceExtension, + NULL, + 0, + deviceExtension->HostTargetId, + 0, + SP_INTERNAL_ADAPTER_ERROR, + 8 << 16 + ); + + return TRUE; + } + +} // end SpockAbortIo() + + +VOID +BuildScb( + IN PHW_DEVICE_EXTENSION DeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb + ) + +/*++ + +Routine Description: + + Build SCB + +Arguments: + + DeviceExtension + SRB + +Return Value: + + Nothing. + +--*/ + +{ + + PSCB scb = Srb->SrbExtension; + ULONG length; + + // + // Check for read capacity CDB. IBM boot devices store IML + // code near the end of the boot device that must be preserved. + // Send the operation specific SCB instead of the generic + // SCSI CDB. + // + + if (Srb->Cdb[0] == SCSIOP_READ_CAPACITY) { + + // + // Call routine to build special SCB. + // + + BuildReadCapacity(DeviceExtension, + Srb); + return; + } + + scb->Command = SCB_COMMAND_SEND_SCSI; + + // + // Set SCB command flags. + // + + // + // Some the spock controllers do not work well with multiple devices. + // If too many errors are detected then disable disconnects. + // + + if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT || + DeviceExtension->ErrorCount > MAXIMUM_ERRORS) { + scb->Command |= SCB_NO_DISCONNECT; + } + + if (Srb->SrbFlags & SRB_FLAGS_DISABLE_SYNCH_TRANSFER) { + scb->Command |= SCB_NO_SYNCHRONOUS_TRANSFER; + } + + // + // Set SCB request control flags. + // + + if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT) { + + // + // Write request. + // + + scb->EnableFlags = SCB_ENABLE_SG_LIST | + SCB_ENABLE_WRITE | + SCB_ENABLE_RETRY_ENABLE | + SCB_ENABLE_TSB_ON_ERROR; + + } else if (Srb->SrbFlags & SRB_FLAGS_DATA_IN) { + + // + // Read request. + // + + scb->EnableFlags = SCB_ENABLE_SG_LIST | + SCB_ENABLE_READ | + SCB_ENABLE_SHORT_TRANSFER | + SCB_ENABLE_RETRY_ENABLE | + SCB_ENABLE_TSB_ON_ERROR; + } else { + + // + // No data transfer. + // + + scb->EnableFlags = SCB_ENABLE_TSB_ON_ERROR; + } + + // + // Set CDB length and copy to SCB. + // + + scb->CdbSize = Srb->CdbLength; + + ScsiPortMoveMemory(scb->Cdb, Srb->Cdb, Srb->CdbLength); + + // + // Build SDL in SCB if data transfer. + // + + if (Srb->DataTransferLength) { + BuildSgl(DeviceExtension, Srb); + } else { + scb->BufferAddress = 0; + scb->BufferLength = 0; + } + + // + // Put physical address of TSB in SCB. + // + + scb->StatusBlock = ScsiPortConvertPhysicalAddressToUlong( + ScsiPortGetPhysicalAddress(DeviceExtension, NULL, + &scb->Tsb, &length)); + + return; + +} // end BuildScb() + + +VOID +BuildSgl( + IN PVOID DeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb + ) + +/*++ + +Routine Description: + + Build scatter/gather descriptor list in SCB. + +Arguments: + + DeviceExtension + SRB + +Return Value: + + Nothing. + +--*/ + +{ + PSCB scb = Srb->SrbExtension; + PVOID dataPointer = Srb->DataBuffer; + ULONG bytesLeft = Srb->DataTransferLength; + PSDL sdl = &scb->Sdl; + ULONG physicalSdl; + ULONG physicalAddress; + ULONG length; + ULONG descriptorCount = 0; + + DebugPrint((3,"BuildSgl: Enter routine\n")); + + // + // Zero first SDL descriptor. + // + + sdl->Descriptor[descriptorCount].Address = 0; + sdl->Descriptor[descriptorCount].Length = 0; + + // + // Get physical SDL address. + // + + physicalSdl = ScsiPortConvertPhysicalAddressToUlong( + ScsiPortGetPhysicalAddress(DeviceExtension, NULL, + sdl, &length)); + + // + // Assume physical memory contiguous for sizeof(SDL) bytes. + // + + ASSERT(length >= sizeof(SDL)); + + // + // Create SDL segment descriptors. + // + + do { + + DebugPrint((3, "BuildSgl: Data buffer %lx\n", dataPointer)); + + // + // Get physical address and length of contiguous + // physical buffer. + // + + physicalAddress = + ScsiPortConvertPhysicalAddressToUlong( + ScsiPortGetPhysicalAddress(DeviceExtension, + Srb, + dataPointer, + &length)); + + DebugPrint((3, "BuildSgl: Physical address %lx\n", physicalAddress)); + DebugPrint((3, "BuildSgl: Data length %lx\n", length)); + DebugPrint((3, "BuildSgl: Bytes left %lx\n", bytesLeft)); + + // + // If length of physical memory is more + // than bytes left in transfer, use bytes + // left as final length. + // + + if (length > bytesLeft) { + length = bytesLeft; + } + + // + // Check for adjacent physical memory descriptors. + // + + if (descriptorCount && + ((sdl->Descriptor[descriptorCount-1].Address + + sdl->Descriptor[descriptorCount-1].Length) == physicalAddress)) { + + DebugPrint((3,"BuildSgl: Concatenate adjacent descriptors\n")); + + sdl->Descriptor[descriptorCount-1].Length += length; + + } else { + + sdl->Descriptor[descriptorCount].Address = physicalAddress; + sdl->Descriptor[descriptorCount].Length = length; + descriptorCount++; + } + + // + // Adjust counts. + // + + dataPointer = (PUCHAR)dataPointer + length; + bytesLeft -= length; + + } while (bytesLeft); + + // + // Write SDL length to SCB. + // + + scb->BufferLength = descriptorCount * sizeof(SG_DESCRIPTOR); + + DebugPrint((3,"BuildSgl: SDL length is %d\n", descriptorCount)); + + // + // Write SDL address to SCB. + // + + scb->BufferAddress = physicalSdl; + + DebugPrint((3,"BuildSgl: SDL address is %lx\n", sdl)); + + DebugPrint((3,"BuildSgl: SCB address is %lx\n", scb)); + + return; + +} // end BuildSgl() + +VOID +BuildReadCapacity( + IN PHW_DEVICE_EXTENSION DeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb + ) + +/*++ + +Routine Description: + + Build SCB for read capacity command. + +Arguments: + + DeviceExtension + SRB + +Return Value: + + Nothing. + +--*/ + +{ + PSCB scb = Srb->SrbExtension; + ULONG length; + + DebugPrint((1, "Spock: BuildReadCapacity: Building spock read capacity\n")); + + // + // Set SCB command. + // + + scb->Command = SCB_COMMAND_READ_CAPACITY; + scb->Command |= SCB_NO_SYNCHRONOUS_TRANSFER | SCB_NO_DISCONNECT; + + scb->EnableFlags = SCB_ENABLE_TSB_ON_ERROR | + SCB_ENABLE_READ | + SCB_ENABLE_BYPASS_BUFFER | + SCB_ENABLE_RETRY_ENABLE; + + // + // Get physical buffer address. + // + + scb->BufferAddress = (ScsiPortConvertPhysicalAddressToUlong( + ScsiPortGetPhysicalAddress(DeviceExtension, + Srb, + Srb->DataBuffer, + &length))); + + scb->BufferLength = Srb->DataTransferLength; + + // + // Put physical address of TSB in SCB. + // + + scb->StatusBlock = ScsiPortConvertPhysicalAddressToUlong( + ScsiPortGetPhysicalAddress(DeviceExtension, NULL, + &scb->Tsb, &length)); + + return; + +} // end BuildReadCapacity() + + +ULONG +McaAdapterPresent( + IN PHW_DEVICE_EXTENSION HwDeviceExtension, + IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo, + IN OUT PULONG AdapterCount, + OUT PBOOLEAN Again + ) + +/*++ + +Routine Description: + + Determine if Spock adapter present in sytem by reading + interrupt status register. + +Arguments: + + HwDeviceExtension - miniport device extension + + ConfigInfo - Supplies the known configuraiton information. + + AdapterCount - Supplies the count of adapter slots which have been tested. + + Again - Returns whether the OS-specific driver should call again. + +Return Value: + + Returns TRUE if adapter exists + +--*/ + +{ + PMCA_REGISTERS baseIoAddress; + PUCHAR ioSpace; + + // + // Get the system physical address for this card. The card uses I/O space. + // + + ioSpace = ScsiPortGetDeviceBase( + HwDeviceExtension, // HwDeviceExtension + ConfigInfo->AdapterInterfaceType, // AdapterInterfaceType + ConfigInfo->SystemIoBusNumber, // SystemIoBusNumber + ScsiPortConvertUlongToPhysicalAddress(0), + 0x400, // NumberOfBytes + TRUE // InIoSpace + ); + + // + // Scan though the adapter address looking for adapters. + // + + while (AdapterAddresses[*AdapterCount] != 0) { + + // + // Check to see if adapter present in system. + // + + baseIoAddress = (PMCA_REGISTERS)(ioSpace + + AdapterAddresses[*AdapterCount]); + + // + // Update the adapter count. + // + + (*AdapterCount)++; + + if (ScsiPortReadPortUchar((PUCHAR)baseIoAddress) != 0xFF) { + + DebugPrint((1,"Spock: Base IO address is %x\n", baseIoAddress)); + + // + // An adapter has been found. Set the base address in the device + // extension, and request another call. + // + + HwDeviceExtension->Registers = baseIoAddress; + *Again = TRUE; + + // + // Fill in the access array information. + // + + (*ConfigInfo->AccessRanges)[0].RangeStart = + ScsiPortConvertUlongToPhysicalAddress( + AdapterAddresses[*AdapterCount - 1]); + (*ConfigInfo->AccessRanges)[0].RangeLength = sizeof(MCA_REGISTERS); + (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE; + + return(SP_RETURN_FOUND); + } + } + + // + // The entire table has been searched and no adapters have been found. + // There is no need to call again and the device base can now be freed. + // Clear the adapter count for the next bus. + // + + *Again = FALSE; + *(AdapterCount) = 0; + + ScsiPortFreeDeviceBase( + HwDeviceExtension, + ioSpace + ); + + return(SP_RETURN_NOT_FOUND); + +} // end McaAdapterPresent() + + +BOOLEAN +IssueScbCommand( + IN PVOID HwDeviceExtension, + IN ULONG PhysicalScb, + IN UCHAR TargetId + ) + +/*++ + +Routine Description: + + Send SCB to adapter. + +Arguments: + + DeviceExtension + Physical SCB + TargeId + +Return Value: + + TRUE if command sent. + FALSE if wait for BUSY bit timed out. + +--*/ + +{ + PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; + PMCA_REGISTERS mcaRegisters = deviceExtension->Registers; + ULONG i; + + // + // Wait up to 10 milliseconds until adapter is not busy. + // + + for (i=0; i<1000; i++) { + + if (ScsiPortReadPortUchar( + &mcaRegisters->BasicStatus) & BASIC_STATUS_BUSY) { + + // + // Wait 10 microseconds. + // + + ScsiPortStallExecution(10); + + } else { + + // + // Busy bit clear. Exit loop. + // + + break; + } + } + + if (i < 1000) { + + // + // Write physical SCB address to command interface register. + // + + ScsiPortWritePortUlong(&mcaRegisters->CommandInterface, PhysicalScb); + + // + // Write targetid and command code to attention register. + // + + ScsiPortWritePortUchar(&mcaRegisters->Attention, (UCHAR)(TargetId | START_SCB)); + + if (!deviceExtension->ActiveRequests++) { + + // + // Turn disk activity light on. + // + + DISK_ACTIVITY_LIGHT_ON(); + } + + return TRUE; + + } else { + + ScsiPortLogError( + deviceExtension, + NULL, + 0, + deviceExtension->HostTargetId, + 0, + SP_INTERNAL_ADAPTER_ERROR, + 4 << 16 + ); + + return FALSE; + } + +} // end IssueScbCommand() + + +BOOLEAN +IssueImmediateCommand( + IN PVOID HwDeviceExtension, + IN ULONG ImmediateCommand, + IN UCHAR TargetId + ) + +/*++ + +Routine Description: + + Send SCB to adapter. + +Arguments: + + DeviceExtension + ImmediateCommand + TargeId + +Return Value: + + TRUE if command sent. + FALSE if wait for BUSY bit timed out. + +--*/ + +{ + PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; + PMCA_REGISTERS mcaRegisters = deviceExtension->Registers; + ULONG i; + + // + // Wait up to 10 milliseconds until adapter is not busy. + // + + for (i=0; i<1000; i++) { + + if (ScsiPortReadPortUchar( + &mcaRegisters->BasicStatus) & BASIC_STATUS_BUSY) { + + // + // Wait 10 microseconds. + // + + ScsiPortStallExecution(10); + + } else { + + // + // Busy bit clear. Exit loop. + // + + break; + } + } + + if (i < 1000) { + + // + // Write immediate command to command interface register. + // + + ScsiPortWritePortUlong(&mcaRegisters->CommandInterface, ImmediateCommand); + + // + // Write targetid and command code to attention register. + // + + ScsiPortWritePortUchar(&mcaRegisters->Attention, + (UCHAR)(TargetId | IMMEDIATE_COMMAND)); + + return TRUE; + + } else { + + ScsiPortLogError( + deviceExtension, + NULL, + 0, + deviceExtension->HostTargetId, + 0, + SP_INTERNAL_ADAPTER_ERROR, + 4 << 16 + ); + + return FALSE; + } + +} // end IssueImmediateCommand() + + +VOID +MapTsbError( + IN PHW_DEVICE_EXTENSION DeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb, + IN PTSB Tsb + ) + +/*++ + +Routine Description: + +Arguments: + + TSB - Termination Status Block + +Return Value: + + SCSI error code + +--*/ + +{ + ULONG logError = 0; + + DebugPrint((2, "MapTsbError: TSB ending status %lx\n", Tsb->ScbStatus)); + + switch (Tsb->ScbStatus & 0x003F) { + + case TSB_STATUS_NO_ERROR: + + // + // Check if device is not assigned. + // + + if (Tsb->CommandError == TSB_COMMAND_ERROR_DEVICE_NOT_ASSIGNED) { + + // + // Check for check condition. + // + + if (Tsb->DeviceStatus == SCB_DEV_STATUS_CHECK_CONDITION) { + + // + // Adjust count of bytes transferred. + // + + Srb->DataTransferLength -= Tsb->ResidualByteCount; + } + + Srb->SrbStatus = SRB_STATUS_NO_DEVICE; + + } else { + + Srb->SrbStatus = SRB_STATUS_ERROR; + } + + break; + + case TSB_STATUS_SHORT_RECORD: + + DebugPrint((1, "MapTsbError: Short record exception\n")); + + Srb->DataTransferLength -= Tsb->ResidualByteCount; + + Srb->SrbStatus = SRB_STATUS_DATA_OVERRUN; + + break; + + case TSB_STATUS_INVALID_COMMAND: + + DebugPrint((1, "MapTsbError: Invalid command rejected\n")); + + Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST; + logError = SP_INTERNAL_ADAPTER_ERROR; + + break; + + case TSB_STATUS_SCB_REJECTED: + + DebugPrint((1, "MapTsbError: SCB rejected\n")); + + Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST; + logError = SP_INTERNAL_ADAPTER_ERROR; + + break; + + case TSB_STATUS_SCB_SPECIFIC_CHECK: + + DebugPrint((1, "MapTsbError: SCB speicific check\n")); + Srb->SrbStatus = SRB_STATUS_ERROR; + logError = SP_INTERNAL_ADAPTER_ERROR; + + break; + + case TSB_STATUS_LONG_RECORD: + + DebugPrint((1, "MapTsbError: Long record exception\n")); + + Srb->SrbStatus = SRB_STATUS_DATA_OVERRUN; + + break; + + default: + + DebugPrint((1, "MapTsbError: Unknown end status %lx\n",Tsb->ScbStatus)); + logError = SP_INTERNAL_ADAPTER_ERROR; + + Srb->SrbStatus = SRB_STATUS_ERROR; + + } // end switch + + DebugPrint((2, + "MapTsbError: Device status %x, DeviceError = %x\n", + Tsb->DeviceStatus, + Tsb->DeviceError)); + DebugPrint((2, + "MapTsbError: Command status %x, CommandError = %x\n", + Tsb->CommandStatus, + Tsb->CommandError)); + + if (logError != 0) { + + // + // Log error. + // + + ScsiPortLogError( + DeviceExtension, + Srb, + Srb->PathId, + Srb->TargetId, + Srb->Lun, + logError, + 2 << 16 | Tsb->ScbStatus + ); + + } + + Srb->ScsiStatus = Tsb->DeviceStatus; + + return; + +} // end MapTsbError() diff --git a/private/ntos/miniport/spock/spock.rc b/private/ntos/miniport/spock/spock.rc new file mode 100644 index 000000000..016f46aa5 --- /dev/null +++ b/private/ntos/miniport/spock/spock.rc @@ -0,0 +1,12 @@ +#include <windows.h> + +#include <ntverp.h> + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM +#define VER_FILEDESCRIPTION_STR "IBM MCA SCSI Controller Driver" +#define VER_INTERNALNAME_STR "spock.sys" +#define VER_ORIGINALFILENAME_STR "spock.sys" + +#include "common.ver" + |