diff options
Diffstat (limited to '')
-rw-r--r-- | private/ntos/miniport/ultra124/ultra124.c | 1617 |
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() + + |