summaryrefslogtreecommitdiffstats
path: root/private/ntos/miniport/ultra124/ultra124.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--private/ntos/miniport/ultra124/ultra124.c1617
1 files changed, 1617 insertions, 0 deletions
diff --git a/private/ntos/miniport/ultra124/ultra124.c b/private/ntos/miniport/ultra124/ultra124.c
new file mode 100644
index 000000000..6b23bcb65
--- /dev/null
+++ b/private/ntos/miniport/ultra124/ultra124.c
@@ -0,0 +1,1617 @@
+/* Copyright (c) 1992 Microsoft/UltrStor Corporation
+
+Module Name:
+ ultra124.c
+
+Abstract:
+ This is the port driver for the ULTRASTOR 124 EISA SCSI adapter.
+
+Authors:
+ Mike Glass / Edward Syu
+
+Environment:
+ kernel mode only
+
+Notes:
+
+Revision History:
+-----------------------------------------------------------------------------
+ Date Name Description
+
+08/25/92 Syu First time created. Modify from 24f source code.
+
+11/04/92 Fong * Change MSCP_TARGET_ERROR from 91h to A0H
+ * Handle Aborted command in Startio
+04/05/93 fong fix Handle Inquiry data problem for MARCH NT release
+-----------------------------------------------------------------------------
+
+--*/
+
+#include "miniport.h"
+#include "ultra124.h" // includes scsi.h
+
+//
+// Device extension
+//
+
+typedef struct _HW_DEVICE_EXTENSION {
+ PEISA_CONTROLLER EisaController;
+ UCHAR HostTargetId;
+ PSCSI_REQUEST_BLOCK CSIRSrb; // byte 24
+} HW_DEVICE_EXTENSION, *PHW_DEVICE_EXTENSION;
+
+
+//
+// Function declarations
+//
+// Functions that start with 'Ultra124' are entry points
+// for the OS port driver.
+//
+
+ULONG
+DriverEntry(
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ );
+
+ULONG
+Ultra124FindAdapter(
+ IN PVOID DeviceExtension,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ );
+
+BOOLEAN
+Ultra124Initialize(
+ IN PVOID DeviceExtension
+ );
+
+BOOLEAN
+Ultra124StartIo(
+ IN PVOID DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+BOOLEAN
+Ultra124Interrupt(
+ IN PVOID DeviceExtension
+ );
+
+BOOLEAN
+Ultra124ResetBus(
+ IN PVOID HwDeviceExtension,
+ IN ULONG PathId
+ );
+
+//
+// This function is called from Ultra124StartIo.
+//
+
+BOOLEAN
+BuildMscp(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+//
+// This function is called from BuildMscp.
+//
+
+VOID
+BuildSgl(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+//
+// This function is called from Ultra124Interrupt.
+//
+
+VOID
+MapErrorToSrbStatus(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+BOOLEAN
+ReadDriveCapacity(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+
+ULONG
+DriverEntry (
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ )
+
+/*++
+
+Routine Description:
+
+ Installable driver initialization entry point for system.
+
+Arguments:
+
+ Driver Object
+
+Return Value:
+
+ Status from ScsiPortInitialize()
+
+--*/
+
+{
+ HW_INITIALIZATION_DATA hwInitializationData;
+ ULONG i;
+ ULONG AdapterCount = 0;
+
+ DebugPrint((1,"\n\nSCSI UltraStor 124 MiniPort 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 = Ultra124Initialize;
+ hwInitializationData.HwFindAdapter = Ultra124FindAdapter;
+ hwInitializationData.HwStartIo = Ultra124StartIo;
+ hwInitializationData.HwInterrupt = Ultra124Interrupt;
+ hwInitializationData.HwResetBus = Ultra124ResetBus;
+
+ //
+ // Set number of access ranges and bus type.
+ //
+
+ hwInitializationData.NumberOfAccessRanges = 1;
+ hwInitializationData.AdapterInterfaceType = Eisa;
+
+ //
+ // Indicate no buffer mapping but will need physical addresses.
+ //
+
+ hwInitializationData.NeedPhysicalAddresses = TRUE;
+
+ //
+ // Indicate multiple requests per LUN is supported.
+ //
+
+ hwInitializationData.MultipleRequestPerLu = TRUE;
+
+ //
+ // Indicate auto request sense is supported.
+ //
+
+ hwInitializationData.AutoRequestSense = TRUE;
+
+ //
+ // Specify size of extensions.
+ //
+
+ hwInitializationData.DeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION);
+
+ //
+ // Ask for SRB extensions for MSCPs.
+ //
+
+ hwInitializationData.SrbExtensionSize = sizeof(MSCP);
+ return ScsiPortInitialize(DriverObject,
+ Argument2,
+ &hwInitializationData,
+ &AdapterCount);
+
+} // end DriverEntry()
+
+
+ULONG
+Ultra124FindAdapter(
+ IN PVOID HwDeviceExtension,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called by the OS-specific port driver after
+ the necessary storage has been allocated, to gather information
+ about the adapter's configuration.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ ConfigInfo - Configuration information structure describing HBA
+
+Return Value:
+
+ TRUE if adapter present in system
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PEISA_CONTROLLER eisaController;
+ ULONG eisaSlotNumber;
+ PVOID eisaAddress;
+ PULONG adapterCount = Context;
+ UCHAR interruptLevel;
+
+ //
+ // Check to see if adapter present in system.
+ //
+
+ for (eisaSlotNumber=*adapterCount + 1;
+ eisaSlotNumber<MAXIMUM_EISA_SLOTS;
+ eisaSlotNumber++) {
+
+ //
+ // Update the adapter count to indicate this slot has been checked.
+ //
+
+ (*adapterCount)++;
+
+ //
+ // Get the system address for this card.
+ // The card uses I/O space.
+ //
+
+ eisaAddress = ScsiPortGetDeviceBase(deviceExtension,
+ ConfigInfo->AdapterInterfaceType,
+ ConfigInfo->SystemIoBusNumber,
+ ScsiPortConvertUlongToPhysicalAddress(0x1000 * eisaSlotNumber),
+ 0x1000,
+ TRUE);
+
+ eisaController =
+ (PEISA_CONTROLLER)((PUCHAR)eisaAddress + EISA_ADDRESS_BASE);
+
+ if (ScsiPortReadPortUlong(&eisaController->BoardId) ==
+ ULTRASTOR_124_EISA_ID) {
+ DebugPrint((1,
+ "Ultra124: Adapter found at EISA slot %d\n",
+ eisaSlotNumber));
+ break;
+ }
+
+ //
+ // If an adapter was not found unmap it.
+ //
+
+ ScsiPortFreeDeviceBase(deviceExtension,
+ eisaAddress);
+
+ } // end for (eisaSlotNumber ...
+
+ if (!(eisaSlotNumber < MAXIMUM_EISA_SLOTS)) {
+
+ //
+ // No adapter was found. Indicate that we are done and there are no
+ // more adapters here. Clear the adapter count for the next bus.
+ //
+
+ *Again = FALSE;
+ *adapterCount = 0;
+ return SP_RETURN_NOT_FOUND;
+ }
+
+ //
+ // There is still more to look at.
+ //
+
+ *Again = TRUE;
+
+ //
+ // Store base address of EISA registers in device extension.
+ //
+
+ deviceExtension->EisaController = eisaController;
+ deviceExtension->HostTargetId = ConfigInfo->InitiatorBusId[0] = 0x07; //fix to 7 for U124
+
+ //
+ // Indicate maximum transfer length in bytes.
+ //
+
+ ConfigInfo->MaximumTransferLength = MAXIMUM_TRANSFER_LENGTH;
+
+ //
+ // Maximum number of physical segments is 32.
+ //
+
+ ConfigInfo->NumberOfPhysicalBreaks = MAXIMUM_SG_DESCRIPTORS;
+ ConfigInfo->ScatterGather = TRUE;
+ ConfigInfo->Master = TRUE;
+ ConfigInfo->NumberOfBuses = 1;
+
+ //
+ // Get the system interrupt vector and IRQL.
+ //
+
+ interruptLevel =
+ ScsiPortReadPortUchar(&eisaController->InterruptLevel) & 0xF0;
+
+ switch (interruptLevel) {
+ case US_INTERRUPT_LEVEL_15:
+ ConfigInfo->BusInterruptLevel = 15;
+ break;
+
+ case US_INTERRUPT_LEVEL_14:
+ ConfigInfo->BusInterruptLevel = 14;
+ break;
+
+ case US_INTERRUPT_LEVEL_11:
+ ConfigInfo->BusInterruptLevel = 11;
+ break;
+
+ case US_INTERRUPT_LEVEL_10:
+ ConfigInfo->BusInterruptLevel = 10;
+ break;
+
+ default:
+ DebugPrint((1,"Ultra124FindAdapter: No interrupt level\n"));
+ return SP_RETURN_ERROR;
+ }
+
+ //
+ // Fill in the access array information.
+ //
+
+ (*ConfigInfo->AccessRanges)[0].RangeStart =
+ ScsiPortConvertUlongToPhysicalAddress(0x1000 * eisaSlotNumber + EISA_ADDRESS_BASE);
+ (*ConfigInfo->AccessRanges)[0].RangeLength = sizeof(EISA_CONTROLLER);
+ (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE;
+
+ return SP_RETURN_FOUND;
+
+} // end Ultra124FindAdapter()
+
+
+BOOLEAN
+Ultra124Initialize(
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ Inititialize adapter.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ TRUE - if initialization successful.
+ FALSE - if initialization unsuccessful.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PEISA_CONTROLLER eisaController = deviceExtension->EisaController;
+
+ DebugPrint((3,"Ultra124Initialize: Enter routine\n"));
+
+
+ //
+ // Enable system doorbell interrupt.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBellMask,
+ US_ENABLE_SYSTEM_INTERRUPT+US_ENABLE_CSIR_INTERRUPT+US_ENABLE_MSCP_INTERRUPT);
+
+ return(TRUE);
+
+} // end Ultra124Initialize()
+
+
+BOOLEAN
+Ultra124StartIo(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called from the SCSI port driver synchronized
+ with the kernel to send an MSCP.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ Srb - IO request packet
+
+Return Value:
+
+ TRUE
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PEISA_CONTROLLER eisaController = deviceExtension->EisaController;
+ PMSCP mscp;
+ PUCHAR mscpbuffer;
+ PSCSI_REQUEST_BLOCK abortedSrb;
+ ULONG physicalMscp;
+ ULONG length;
+ ULONG i = 0;
+
+ DebugPrint((2,"Ultra124StartIo: Enter routine\n"));
+
+ //DEBUGSTOP();
+
+ ASSERT(Srb->SrbStatus == SRB_STATUS_PENDING);
+
+ //
+ // Make sure that the request is for a valid SCSI bus and LUN as
+ // the Ultra124 SCSI card does random things if address is wrong.
+ //
+
+ if (Srb->PathId != 0 || Srb->Lun != 0) {
+
+ //
+ // The Ultra124 card only supports logical unit zero and one bus.
+ //
+ DebugPrint((1,"Ultra124StartIo: Invalid LUN\n"));
+
+ Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+ //
+ // Adapter ready for next request.
+ //
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ return TRUE;
+ }
+
+ //
+ // Get MSCP from SRB.
+ //
+
+ mscp = Srb->SrbExtension;
+ mscpbuffer = (PUCHAR) mscp;
+
+ for (i=0; i<sizeof(MSCP); i++) //initialize as 0
+ (UCHAR) mscpbuffer[i] = 0;
+
+ //
+ // Save SRB back pointer in MSCP.
+ //
+
+ mscp->SrbAddress = Srb;
+
+ //
+ // Get MSCP physical address.
+ //
+
+ physicalMscp =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(deviceExtension, NULL, mscp, &length));
+
+ //
+ // Assume physical address is contiguous for size of ECB.
+ //
+
+ ASSERT(length >= sizeof(MSCP));
+
+ switch (Srb->Function) {
+
+ case SRB_FUNCTION_EXECUTE_SCSI:
+ DebugPrint((3,"Ultra124StartIo: SCSI Execute IO\n"));
+
+ if (Srb->Cdb[0] == SCSIOP_READ_CAPACITY) {
+ DebugPrint((3,"Ultra124StartIo: SCSI Read Capacity\n"));
+
+ if (ReadDriveCapacity(deviceExtension, Srb)) {
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ return TRUE;
+ }
+ else {
+ Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ return TRUE;
+ }
+ }
+ else {
+ //
+ // Build MSCP for this request.
+ //
+ if (!(BuildMscp(deviceExtension, Srb))) {
+ //
+ // Set error, complete request
+ // and signal ready for next request.
+ //
+ DebugPrint((1,"Ultra124StartIo: BuildMscp Fail\n"));
+ Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ return TRUE;
+ }
+
+ }
+ break;
+
+//{$8_24
+ case SRB_FUNCTION_RESET_BUS:
+
+ //
+ // Reset Ultra124 and SCSI bus.
+ //
+
+ DebugPrint((1, "Ultra124StartIo: Reset bus request received\n"));
+
+ if (!Ultra124ResetBus( deviceExtension, Srb->PathId)) {
+ DebugPrint((1,"Ultra124StartIo: Reset bus failed\n"));
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+ }
+ else {
+ DebugPrint((1,"Ultra124StartIo: Reset bus O.K.\n"));
+ Srb->SrbStatus = SRB_STATUS_SUCCESS;
+ }
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ return TRUE;
+
+//$11_4
+ case SRB_FUNCTION_ABORT_COMMAND:
+
+ DebugPrint((1, "Ultra124StartIo: Received Abort command\n"));
+ //
+ // Verify that SRB to abort is still outstanding.
+ //
+
+ abortedSrb = ScsiPortGetSrb(deviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun,
+ Srb->QueueTag);
+
+ if (abortedSrb != Srb->NextSrb ||
+ abortedSrb->SrbStatus != SRB_STATUS_PENDING) {
+
+ DebugPrint((1, "Ultra124StartIo: SRB to abort already completed\n"));
+
+ //
+ // Complete abort SRB.
+ //
+ Srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+ //
+ // Adapter ready for next request.
+ //
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ }
+ else {
+
+ abortedSrb->SrbStatus = SRB_STATUS_ABORTED;
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ abortedSrb);
+ //
+ // Complete abort SRB.
+ //
+
+ Srb->SrbStatus = SRB_STATUS_SUCCESS;
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+
+ //
+ // Adapter ready for next request.
+ //
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ }
+ return TRUE;
+
+//$8_24}
+ default:
+
+ //
+ // Set error, complete request
+ // and signal ready for next request.
+ //
+
+ DebugPrint((1,"Ultra124StartIo: Request Not Support\n"));
+
+ Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ return TRUE;
+
+ } // end switch
+
+ //
+ // Write MSCP pointer and command to mailbox.
+ //
+
+
+ DebugPrint((3,"Ultra124StartIo: Check if OGM available\n"));
+
+ for (i=0; i<500; i++) {
+
+ if (!(ScsiPortReadPortUchar(&eisaController->LocalDoorBellInterrupt) & US_MSCP_IN_USE)) {
+ break;
+ }
+ else {
+ //
+ // Stall 1 microsecond before trying again.
+ //
+ ScsiPortStallExecution(1);
+ }
+ }
+
+ if (i == 500) {
+ //
+ // Let operating system time out SRB.
+ //
+ DebugPrint((1,"Ultra124StartIo: Timed out waiting for mailbox\n"));
+ //
+ // Set error, complete request
+ // and signal ready for next request.
+ //
+ Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ return TRUE;
+
+ }
+ else {
+
+ //
+ // Write MSCP pointer to mailbox.
+ //
+ DebugPrint((2,"Ultra124StartIo: Send out OGM (Log.Addr %lx)\n",mscp));
+ ScsiPortWritePortUlong(&eisaController->OutGoingMailPointer,
+ physicalMscp);
+ //
+ // Send MAIL OUT
+ // Ring the local doorbell.
+ //
+ ScsiPortWritePortUchar(&eisaController->LocalDoorBellInterrupt,
+ US_MSCP_IN_USE);
+ }
+
+ //
+ // Adapter ready for next request.
+ //
+ ScsiPortNotification(NextLuRequest,
+ deviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun);
+
+ return TRUE;
+
+} // end Ultra124StartIo()
+
+
+BOOLEAN
+Ultra124Interrupt(
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ This is the interrupt service routine for the Ultra124 SCSI adapter.
+ It reads the interrupt register to determine if the adapter is indeed
+ the source of the interrupt and clears the interrupt at the device.
+ If the adapter is interrupting because a mailbox is full, the MSCP is
+ retrieved to complete the request.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ TRUE if MailboxIn full
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PMSCP mscp;
+ PSCSI_REQUEST_BLOCK srb;
+ PEISA_CONTROLLER eisaController = deviceExtension->EisaController;
+ ULONG physicalMscp;
+ UCHAR mscpStatus, csirStatus;
+ UCHAR InterruptMode;
+ UCHAR CDBOpcode;
+ ULONG BlockSize, TotalBlock;
+ PINQUIRYDATA InquiryBuffer;
+ PSCSI_READCAPACITY ReadCapacityBuffer;
+
+ CONST UCHAR VendorId[] = "ULTRSTOR";
+ CONST UCHAR ProductId[] = "U124 DiskArray ";
+ CONST UCHAR ProductRevisionLevel[] = "1.00";
+ UCHAR i;
+
+ //
+ // Check interrupt pending.
+ //
+ // Check CSIR command
+
+
+ DebugPrint((2,"Ultra124Interrupt: Enter routine\n"));
+
+ //DEBUGSTOP();
+
+
+ InterruptMode = ScsiPortReadPortUchar(&eisaController->SystemDoorBellInterrupt);
+
+ InterruptMode &= US_CSIR_COMPLETE + US_MSCP_COMPLETE;
+
+ switch (InterruptMode) {
+
+ case US_CSIR_COMPLETE:
+
+ DebugPrint((3, "U124Interrupt: CSIR interrupt\n"));
+
+ csirStatus = ScsiPortReadPortUchar(&eisaController->CSPByte0);
+
+ srb = deviceExtension->CSIRSrb;
+
+ if (!(csirStatus & CSIR_ERROR)) {
+
+ CDBOpcode = srb->Cdb[0];
+
+ switch (CDBOpcode) {
+
+ case SCSIOP_READ_CAPACITY:
+
+ TotalBlock = ScsiPortReadPortUlong((PULONG)(&eisaController->CSPByte2));
+ BlockSize = 0x200;
+ DebugPrint((3, "U124Interrupt(ReadCapacity): TotalBock %ld\n",TotalBlock ));
+ ReadCapacityBuffer = (PSCSI_READCAPACITY) srb->DataBuffer;
+ DebugPrint((3, "U124Interrupt: SRB Data Buffer -> %lx\n",
+ srb->DataBuffer));
+ DebugPrint((3, "U124Interrupt: Inquiry Buffer -> %lx\n",
+ ReadCapacityBuffer));
+ INTEL4_TO_SCSI4((PSCSI_4_BYTE) ReadCapacityBuffer->BlockCount,
+ (PINTEL_4_BYTE) &TotalBlock);
+ INTEL4_TO_SCSI4((PSCSI_4_BYTE) ReadCapacityBuffer->BlockLength,
+ (PINTEL_4_BYTE) &BlockSize);
+ break;
+
+ default:
+ break;
+ }
+
+ srb->SrbStatus = SRB_STATUS_SUCCESS;
+ srb->ScsiStatus = SCSISTAT_GOOD;
+
+ }
+ else {
+ DebugPrint((1, "U124Interrupt: CSIR interrupt with Error\n"));
+ MapErrorToSrbStatus(deviceExtension, srb);
+ }
+
+ // Call notification routine for the SRB.
+
+ ScsiPortNotification( RequestComplete,
+ (PVOID)deviceExtension,
+ srb);
+
+ // Reset system doorbell interrupt.
+
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBellInterrupt,
+ US_RESET_CSIR_COMPLETE);
+
+ return TRUE;
+
+ case US_MSCP_COMPLETE:
+
+ DebugPrint((3, "U124Interrupt: MSCP interrupt\n"));
+ physicalMscp = ScsiPortReadPortUlong(&eisaController->InComingMailPointer);
+ //
+ // Get virtual MSCP address.
+ //
+ mscp = ScsiPortGetVirtualAddress(deviceExtension,
+ ScsiPortConvertUlongToPhysicalAddress(physicalMscp));
+ //
+ // Make sure the physical address was valid.
+ //
+ if (mscp == NULL) {
+ DebugPrint((1,"Ultra124Interrupt: No MSCP found\n"));
+ // Reset system doorbell interrupt.
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBellInterrupt,
+ US_RESET_MSCP_COMPLETE);
+
+ return FALSE;
+ }
+
+ srb = mscp->SrbAddress; // get SRB
+ if (srb == NULL) {
+
+ DebugPrint((1, "U124Interrupt: Srb in MSCP is NULL.\n"));
+
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBellInterrupt,
+ US_RESET_MSCP_COMPLETE);
+ return FALSE;
+ }
+
+ DebugPrint((2, "U124Interrupt: MSCP Log. Addr ->%lx\n",mscp));
+ DebugPrint((2, "U124Interrupt: SRB Log. Addr ->%lx\n",srb));
+ mscpStatus = mscp->OperationCode; //Error Code
+
+ if (mscpStatus & MSCP_ERROR) {
+
+ //
+ // Translate adapter status to SRB status
+ // and log error if necessary.
+ //
+
+ DebugPrint((1, "U124Interrupt: MSCP Done Fail.\n"));
+ MapErrorToSrbStatus(deviceExtension, srb);
+ }
+ else {
+ DebugPrint((3, "U124Interrupt: MSCP Status O.K.\n"));
+ CDBOpcode = srb->Cdb[0];
+
+ switch (CDBOpcode) {
+ case SCSIOP_INQUIRY:
+ DebugPrint((3, "U124Interrupt: SCSI Inquiry Command done\n"));
+
+ InquiryBuffer = (PINQUIRYDATA) srb->DataBuffer;
+
+ //
+ // clear the InquiryBuffer before filling in data to avoid
+ // garbage data in buffer (because some field in Inquiry data
+ // structure are defined in bits value.
+ //
+
+ for (i=0; i<srb->DataTransferLength; i++) {
+ *((PUCHAR) InquiryBuffer+i) = 0;
+ }
+
+ DebugPrint((3, "U124Interrupt: SRB Data Buffer -> %lx\n",
+ srb->DataBuffer));
+
+ DebugPrint((3, "U124Interrupt: Inquiry Buffer -> %lx\n",
+ InquiryBuffer));
+ InquiryBuffer->DeviceType = DIRECT_ACCESS_DEVICE;
+ InquiryBuffer->DeviceTypeModifier = 0; //not removable
+
+ InquiryBuffer->Versions = 0x02; //scsi 2
+ InquiryBuffer->ResponseDataFormat = 0x02; //scsi 2
+ InquiryBuffer->AdditionalLength = 0x8f; //scsi 2
+
+ InquiryBuffer->SoftReset = 0; //scsi 2
+ InquiryBuffer->CommandQueue = 1;
+ InquiryBuffer->Reserved2 = 0;
+ InquiryBuffer->LinkedCommands = 1;
+ InquiryBuffer->Synchronous = 1;
+ InquiryBuffer->Wide16Bit = 0;
+ InquiryBuffer->Wide32Bit = 0;
+ InquiryBuffer->RelativeAddressing = 1;
+
+ for (i=0; i<8; i++)
+ (UCHAR) InquiryBuffer->VendorId[i] = (UCHAR) VendorId[i];
+
+ for (i=0; i<16; i++)
+ (UCHAR) InquiryBuffer->ProductId[i] = (UCHAR) ProductId[i];
+
+ for (i=0; i<4; i++)
+ (UCHAR) InquiryBuffer->ProductRevisionLevel[i] = (UCHAR) ProductRevisionLevel[i];
+
+ break;
+
+ default:
+ DebugPrint((2, "U124Interrupt: SCSI command -> %x\n", CDBOpcode));
+ break;
+ }
+ srb->SrbStatus = SRB_STATUS_SUCCESS;
+ srb->ScsiStatus = SCSISTAT_GOOD;
+ }
+ //
+ // Call notification routine for the SRB.
+ //
+ ScsiPortNotification(RequestComplete,
+ (PVOID)deviceExtension,
+ srb);
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBellInterrupt,
+ US_RESET_MSCP_COMPLETE);
+
+ return TRUE;
+
+ default:
+ //
+ // Handle spurious interrupt.
+ //
+ DebugPrint((1,"Ultra124Interrupt: Spurious interrupt\n"));
+ //
+ // Log the error.
+ //
+
+ ScsiPortLogError(HwDeviceExtension,
+ NULL,
+ 0,
+ deviceExtension->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 0
+ );
+
+ return FALSE;
+
+ }
+
+
+} // end Ultra124Interrupt()
+
+
+BOOLEAN
+BuildMscp(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ Build MSCP for Ultra124 from SRB.
+
+Arguments:
+
+ DeviceExtenson
+ SRB
+
+Return Value:
+ TRUE: MSCP command ready to send
+ FALSE: no U124 command match this SCSI pass thru command
+--*/
+
+{
+ PMSCP mscp = Srb->SrbExtension;
+ UCHAR CDBopcode;
+
+
+ DebugPrint((3,"BuildMscp: Enter routine\n"));
+
+ //
+ // Set MSCP command.
+ //
+
+ mscp->DriveControl = Srb->TargetId << 5;
+ CDBopcode = Srb->Cdb[0]; //get SCSI CDB opcode
+ DebugPrint((2, "U124BuildMSCP: SCSI command -> %x\n", CDBopcode));
+
+ switch (CDBopcode) {
+ case SCSIOP_INQUIRY:
+ mscp->OperationCode = MSCP_TEST_DRIVE_READY; //use for inquiry
+ break;
+
+ case SCSIOP_TEST_UNIT_READY:
+ mscp->OperationCode = MSCP_TEST_DRIVE_READY;
+ break;
+
+ case SCSIOP_REZERO_UNIT:
+ mscp->OperationCode = MSCP_REZERO_DRIVE;
+ break;
+
+ case SCSIOP_READ:
+ mscp->OperationCode = MSCP_READ_SECTOR;
+ SCSI4_TO_INTEL4((PINTEL_4_BYTE)&mscp->DriveLBA, (PSCSI_4_BYTE)&Srb->Cdb[C10_LBA_4]);
+ break;
+
+ case SCSIOP_READ6:
+ mscp->OperationCode = MSCP_READ_SECTOR;
+ SCSI2_TO_INTEL4((PINTEL_4_BYTE)&mscp->DriveLBA, (PSCSI_2_BYTE)&Srb->Cdb[C6_LBA_2]);
+ break;
+
+ case SCSIOP_WRITE:
+ mscp->OperationCode = MSCP_WRITE_SECTOR;
+ SCSI4_TO_INTEL4((PINTEL_4_BYTE)&mscp->DriveLBA, (PSCSI_4_BYTE)&Srb->Cdb[C10_LBA_4]);
+ break;
+
+ case SCSIOP_WRITE6:
+ mscp->OperationCode = MSCP_WRITE_SECTOR;
+ SCSI2_TO_INTEL4((PINTEL_4_BYTE)&mscp->DriveLBA, (PSCSI_2_BYTE)&Srb->Cdb[C6_LBA_2]);
+ break;
+
+ case SCSIOP_VERIFY:
+ mscp->OperationCode = MSCP_VERIFY_SECTOR;
+ SCSI4_TO_INTEL4((PINTEL_4_BYTE)&mscp->DriveLBA, (PSCSI_4_BYTE)&Srb->Cdb[C10_LBA_4]);
+ break;
+
+ case SCSIOP_VERIFY6:
+ mscp->OperationCode = MSCP_VERIFY_SECTOR;
+ SCSI2_TO_INTEL4((PINTEL_4_BYTE)&mscp->DriveLBA, (PSCSI_2_BYTE)&Srb->Cdb[C6_LBA_2]);
+ break;
+
+ case SCSIOP_SEEK:
+ mscp->OperationCode = MSCP_SEEK_DRIVE;
+ SCSI4_TO_INTEL4((PINTEL_4_BYTE)&mscp->DriveLBA, (PSCSI_4_BYTE)&Srb->Cdb[C10_LBA_4]);
+ break;
+
+ case SCSIOP_SEEK6:
+ mscp->OperationCode = MSCP_SEEK_DRIVE;
+ SCSI2_TO_INTEL4((PINTEL_4_BYTE)&mscp->DriveLBA, (PSCSI_2_BYTE)&Srb->Cdb[C6_LBA_2]);
+ break;
+
+ default:
+ return FALSE; // no U124 command match this SCSI pass thru command
+ break;
+
+ }
+
+ //
+ // Build SGL in MSCP if data transfer.
+ //
+ if (Srb->DataTransferLength > 0) {
+ //
+ // Build scattergather descriptor list.
+ //
+ BuildSgl(DeviceExtension, Srb);
+ }
+ else {
+ //
+ // Set up MSCP for no data transfer.
+ //
+ mscp->DataLength = 0;
+ mscp->SgDescriptorCount = 0;
+ }
+ DebugPrint((2, "U124StartIO: Build MSCP done, MSCP-> %lx\n",mscp));
+
+ return TRUE;
+
+} // end BuildMscp()
+
+
+VOID
+BuildSgl(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine builds a scatter/gather descriptor list in the MSCP.
+
+Arguments:
+
+ DeviceExtension
+ Srb
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PVOID dataPointer = Srb->DataBuffer;
+ ULONG bytesLeft = Srb->DataTransferLength;
+ PMSCP mscp = Srb->SrbExtension;
+ PSDL sdl = &mscp->Sdl;
+ ULONG physicalSdl;
+ ULONG physicalAddress;
+ ULONG length;
+ ULONG descriptorCount = 0;
+
+ //
+ // Get physical SDL address.
+ //
+
+ physicalSdl = ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension, NULL,
+ sdl, &length));
+
+ //
+ // Assume physical memory contiguous for sizeof(SGL) 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, "Sgl: 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;
+ }
+
+ sdl->Descriptor[descriptorCount].Address = physicalAddress;
+ sdl->Descriptor[descriptorCount].Length = length;
+
+ //
+ // Adjust counts.
+ //
+
+ dataPointer = (PUCHAR)dataPointer + length;
+ bytesLeft -= length;
+ descriptorCount++;
+
+ } while (bytesLeft);
+
+ //
+ // Check for only one descriptor. As an optimization, in these
+ // cases, use nonscattergather requests.
+ //
+
+ if (descriptorCount == 1) {
+ //
+ // Set descriptor count to 0.
+ //
+ mscp->SgDescriptorCount = 0;
+
+ //
+ // Set data pointer to data buffer.
+ //
+ mscp->DataPointer = physicalAddress;
+
+ //
+ // Set data transfer length.
+ //
+ mscp->DataLength = Srb->DataTransferLength;
+
+ //
+ // Clear scattergather bit.
+ //
+
+ }
+ else {
+ //
+ // Write SDL count to MSCP.
+ //
+ mscp->SgDescriptorCount = (UCHAR)descriptorCount;
+
+ //
+ // Write SGL address to ECB.
+ //
+ mscp->DataPointer = physicalSdl;
+ mscp->DataLength = Srb->DataTransferLength;
+
+ //
+ // Indicate scattergather operation.
+ //
+ mscp->DriveControl |= EnableScatterGather;
+ }
+
+ DebugPrint((2,"BuildSgl: SG-> %d, XfrBuffer-> %lx, XfrLength-> %lx\n",
+ descriptorCount, mscp->DataPointer, mscp->DataLength));
+ return;
+
+} // end BuildSgl()
+
+
+BOOLEAN
+Ultra124ResetBus(
+ IN PVOID HwDeviceExtension,
+ IN ULONG PathId
+)
+
+/*++
+
+Routine Description:
+
+ Reset Ultra124 SCSI adapter and SCSI bus.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ Nothing.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PEISA_CONTROLLER eisaController = deviceExtension->EisaController;
+ ULONG j;
+
+ //
+ // The Ultra124 only supports a single SCSI channel.
+ //
+
+
+
+ UNREFERENCED_PARAMETER(PathId);
+ DebugPrint((1,"ResetBus: Reset Ultra124 and SCSI bus\n"));
+ DebugPrint((3,"Ultra124ResetBUS: Enter routine\n"));
+
+ //
+ // Reset SCSI bus (use Reset HostAdapter).
+ //
+ ScsiPortWritePortUchar(&eisaController->LocalDoorBellInterrupt,
+ US_HBA_RESET);
+
+ //
+ // Wait for local processor to clear reset bit.
+ //
+ for (j=0; j<200000; j++) {
+ if (!(ScsiPortReadPortUchar(&eisaController->LocalDoorBellInterrupt) &
+ US_HBA_RESET)) {
+ DebugPrint((1,"Ultra124ResetBUS: Reset H/A O.K.\n"));
+ break;
+ }
+
+ ScsiPortStallExecution(10);
+
+ } // end for (j=0 ...
+
+
+ if (j == 200000) {
+ DebugPrint((1,"Ultra124ResetBUS: Reset H/A Fail\n"));
+ //
+ // Busy has not gone low. Assume the card is gone.
+ // Log the error and fail the request.
+ //
+ ScsiPortLogError(deviceExtension,
+ NULL,
+ 0,
+ deviceExtension->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 3 << 16);
+
+ return FALSE;
+
+ }
+ DebugPrint((1,"Ultra124ResetBUS: Reset H/A Fail\n"));
+
+ //
+ // Complete all outstanding requests.
+ //
+ ScsiPortCompleteRequest(deviceExtension,
+ (UCHAR)0,
+ (UCHAR)-1,
+ (UCHAR)-1,
+ SRB_STATUS_BUS_RESET);
+
+ return TRUE;
+
+} // end Ultra124ResetBus()
+
+
+VOID
+MapErrorToSrbStatus(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ Translate Ultra124 error to SRB error.
+
+Arguments:
+
+ Device Extension for logging error
+ SRB
+
+Return Value:
+
+ Updated SRB
+
+--*/
+
+{
+ ULONG logError = 0;
+ UCHAR srbStatus;
+ PMSCP mscp = Srb->SrbExtension;
+ PUCHAR mscpbuffer;
+ PSENSE_DATA sensebuffer = Srb->SenseInfoBuffer;
+ UCHAR i;
+
+ DebugPrint((3,"Ultra124MapErrorToSrbStatus: Enter routine\n"));
+ mscpbuffer = (PUCHAR) Srb->SrbExtension;
+ Srb->ScsiStatus = SCSISTAT_GOOD; //only check-condition set when TARGET error
+
+ switch (mscp->OperationCode) {
+ case MSCP_TARGET_ERROR:
+
+ //
+ // clear the sensebuffer to 0
+ //
+ for (i=0; i< Srb->SenseInfoBufferLength; i++) {
+ *((PUCHAR) sensebuffer+i) = 0;
+ }
+
+ DebugPrint((1,"MapErrorToSrbStatus: HA_TARGET_ERROR\n"));
+ DebugPrint((1,"MapErrorToSrbStatus: srb->SenseInfoBufferLength = %d\n",Srb->SenseInfoBufferLength));
+
+ sensebuffer->SenseKey = (UCHAR) mscpbuffer[7];
+ sensebuffer->AdditionalSenseCode = (UCHAR) mscpbuffer[6];
+ sensebuffer->AdditionalSenseCodeQualifier = (UCHAR) mscpbuffer[5];
+ Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
+ srbStatus = SRB_STATUS_ERROR | SRB_STATUS_AUTOSENSE_VALID;
+ break;
+
+ case MSCP_DRIVE_FAULT:
+ DebugPrint((1,"MapErrorToSrbStatus: Device not found\n"));
+ srbStatus = SRB_STATUS_NO_DEVICE;
+ break;
+
+ case MSCP_DRIVE_NOT_PRESENT:
+ case MSCP_LOG_DRIVE_UNDEFINE:
+ case MSCP_LOG_DRIVE_NOT_READY:
+ DebugPrint((1,"MapErrorToSrbStatus: MSCP_LOG_DRIVE_NOT_READY\n"));
+ srbStatus = SRB_STATUS_SELECTION_TIMEOUT;
+ break;
+
+ case MSCP_ADAPTER_ERROR:
+ switch ((UCHAR) mscpbuffer[7]) {
+ case HA_SELECTION_TIME_OUT:
+ DebugPrint((1,"MapErrorToSrbStatus: HA_SELECTION_TIME_OUT\n"));
+ srbStatus = SRB_STATUS_SELECTION_TIMEOUT;
+ break;
+
+ case HA_DATA_OVER_UNDER_RUN:
+ DebugPrint((1,"MapErrorToSrbStatus: HA_DATA_OVER_UNDER_RUN\n"));
+ logError = SP_PROTOCOL_ERROR;
+ srbStatus = SRB_STATUS_DATA_OVERRUN;
+ break;
+
+ case HA_BUS_FREE_ERROR:
+ DebugPrint((1,"MapErrorToSrbStatus: HA_BUS_FREE\n"));
+ logError = SP_PROTOCOL_ERROR;
+ srbStatus = SRB_STATUS_UNEXPECTED_BUS_FREE;
+ break;
+
+ case HA_INVALID_PHASE:
+ DebugPrint((1,"MapErrorToSrbStatus: HA_INVALID_PHASE\n"));
+ logError = SP_PROTOCOL_ERROR;
+ srbStatus = SRB_STATUS_PHASE_SEQUENCE_FAILURE;
+ break;
+
+ case HA_ILLEGAL_COMMAND:
+ DebugPrint((1,"MapErrorToSrbStatus: HA_ILLEGAL_COMMAND\n"));
+ srbStatus = SRB_STATUS_INVALID_REQUEST;
+ break;
+
+ case HA_REQ_SENSE_ERROR:
+ DebugPrint((1,"MapErrorToSrbStatus: HA_REQ_SENSE_ERROR\n"));
+ srbStatus = SRB_STATUS_REQUEST_SENSE_FAILED;
+ break;
+
+ case HA_BUS_RESET_ERROR:
+ DebugPrint((1,"MapErrorToSrbStatus: HA_BUS_RESET_ERROR\n"));
+ srbStatus = SRB_STATUS_BUS_RESET;
+ break;
+
+ case HA_TIME_OUT_ERROR:
+ DebugPrint((1,"MapErrorToSrbStatus: HA_DATA_TIME_OUT_ERROR\n"));
+ srbStatus = SRB_STATUS_COMMAND_TIMEOUT;
+ break;
+
+ default:
+ DebugPrint((1,"MapErrorToSrbStatus: General Failure\n"));
+ srbStatus = SRB_STATUS_ERROR;
+
+ }
+ break;
+
+ case MSCP_INVALID_COMMAND:
+ case MSCP_INVALID_PARAMETER:
+ case MSCP_INVALID_DATA_LIST:
+ DebugPrint((1,"MapErrorToSrbStatus: Invalid command\n"));
+ srbStatus = SRB_STATUS_INVALID_REQUEST;
+ break;
+
+ default:
+ DebugPrint((1,"MapErrorToSrbStatus: Unknown Error\n"));
+ logError = SP_PROTOCOL_ERROR;
+ srbStatus = SRB_STATUS_ERROR;
+ break;
+
+ } // end switch ...
+
+ //
+ // Log error if indicated.
+ //
+
+ if (logError) {
+ ScsiPortLogError(
+ DeviceExtension,
+ Srb,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun,
+ logError,
+ 2 << 16 | mscp->OperationCode
+ );
+ }
+
+ //
+ // Set SRB status.
+ //
+ Srb->SrbStatus = srbStatus;
+
+ //
+ // Set target SCSI status in SRB.
+ //
+ return;
+
+} // end MapErrorToSrbStatus()
+
+
+BOOLEAN
+ReadDriveCapacity(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ Build Read Drive Capacity CSIR command from SRB
+
+Arguments:
+
+ DeviceExtenson
+ SRB
+
+Return Value:
+ TRUE: CSIR command
+ FALSE: CSIR command not ready
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = DeviceExtension;
+ PEISA_CONTROLLER eisaController = deviceExtension->EisaController;
+ PMSCP mscp = Srb->SrbExtension;
+ ULONG i;
+ UCHAR CDBopcode;
+
+
+ DebugPrint((3,"ReadDriveCapcity: Enter routine\n"));
+
+ //
+ // Set CSIR command.
+ //
+
+ deviceExtension->CSIRSrb = Srb; //save for later reference
+ CDBopcode = Srb->Cdb[0]; //get SCSI CDB opcode
+ mscp->CSIRBuffer.CSIROpcode = CSIR_READ_CAPACITY;
+ mscp->CSIRBuffer.CSIR1 = (Srb->TargetId) << 5; //drive ID
+ ScsiPortWritePortUchar(&eisaController->CSPByte0,
+ CSIR_READ_CAPACITY);
+ ScsiPortWritePortUchar(&eisaController->CSPByte1,
+ mscp->CSIRBuffer.CSIR1);
+
+ for (i=0; i<500; i++) {
+ if (!(ScsiPortReadPortUchar(&eisaController->LocalDoorBellInterrupt) &
+ US_CSIR_IN_USE)) {
+
+ DebugPrint((3,"Ultra124StartIo: Read Capacity (CSIR)\n"));
+ break;
+ }
+ else {
+ //
+ // Stall 1 microsecond before trying again.
+ //
+ ScsiPortStallExecution(1);
+ }
+ }
+
+ if (i == 500) {
+ //
+ // Let operating system time out SRB.
+ //
+ DebugPrint((1,"Ultra124StartIo: Timed out waiting for CSIR\n"));
+ return FALSE;
+
+ }
+ else {
+ //
+ // Send CSIR command IN
+ // Ring the local doorbell.
+ //
+
+ DebugPrint((1,"Ultra124StartIo: Send out CSIR\n"));
+ ScsiPortWritePortUchar(&eisaController->LocalDoorBellInterrupt,
+ US_CSIR_IN_USE);
+
+ }
+
+ return TRUE;
+
+} // end ReadDriveCapacity()
+
+