📄 buslogic.c
字号:
/* BusLogic_Command sends the command OperationCode to HostAdapter, optionally providing ParameterLength bytes of ParameterData and receiving at most ReplyLength bytes of ReplyData; any excess reply data is received but discarded. On success, this function returns the number of reply bytes read from the Host Adapter (including any discarded data); on failure, it returns -1 if the command was invalid, or -2 if a timeout occurred. BusLogic_Command is called exclusively during host adapter detection and initialization, so performance and latency are not critical, and exclusive access to the Host Adapter hardware is assumed. Once the host adapter and driver are initialized, the only Host Adapter command that is issued is the single byte Execute Mailbox Command operation code, which does not require waiting for the Host Adapter Ready bit to be set in the Status Register.*/static int BusLogic_Command(struct BusLogic_HostAdapter *HostAdapter, enum BusLogic_OperationCode OperationCode, void *ParameterData, int ParameterLength, void *ReplyData, int ReplyLength){ unsigned char *ParameterPointer = (unsigned char *) ParameterData; unsigned char *ReplyPointer = (unsigned char *) ReplyData; union BusLogic_StatusRegister StatusRegister; union BusLogic_InterruptRegister InterruptRegister; unsigned long ProcessorFlags = 0; int ReplyBytes = 0, Result; long TimeoutCounter; /* Clear out the Reply Data if provided. */ if (ReplyLength > 0) memset(ReplyData, 0, ReplyLength); /* If the IRQ Channel has not yet been acquired, then interrupts must be disabled while issuing host adapter commands since a Command Complete interrupt could occur if the IRQ Channel was previously enabled by another BusLogic Host Adapter or another driver sharing the same IRQ Channel. */ if (!HostAdapter->IRQ_ChannelAcquired) local_irq_save(ProcessorFlags); /* Wait for the Host Adapter Ready bit to be set and the Command/Parameter Register Busy bit to be reset in the Status Register. */ TimeoutCounter = 10000; while (--TimeoutCounter >= 0) { StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); if (StatusRegister.sr.HostAdapterReady && !StatusRegister.sr.CommandParameterRegisterBusy) break; udelay(100); } if (TimeoutCounter < 0) { BusLogic_CommandFailureReason = "Timeout waiting for Host Adapter Ready"; Result = -2; goto Done; } /* Write the OperationCode to the Command/Parameter Register. */ HostAdapter->HostAdapterCommandCompleted = false; BusLogic_WriteCommandParameterRegister(HostAdapter, OperationCode); /* Write any additional Parameter Bytes. */ TimeoutCounter = 10000; while (ParameterLength > 0 && --TimeoutCounter >= 0) { /* Wait 100 microseconds to give the Host Adapter enough time to determine whether the last value written to the Command/Parameter Register was valid or not. If the Command Complete bit is set in the Interrupt Register, then the Command Invalid bit in the Status Register will be reset if the Operation Code or Parameter was valid and the command has completed, or set if the Operation Code or Parameter was invalid. If the Data In Register Ready bit is set in the Status Register, then the Operation Code was valid, and data is waiting to be read back from the Host Adapter. Otherwise, wait for the Command/Parameter Register Busy bit in the Status Register to be reset. */ udelay(100); InterruptRegister.All = BusLogic_ReadInterruptRegister(HostAdapter); StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); if (InterruptRegister.ir.CommandComplete) break; if (HostAdapter->HostAdapterCommandCompleted) break; if (StatusRegister.sr.DataInRegisterReady) break; if (StatusRegister.sr.CommandParameterRegisterBusy) continue; BusLogic_WriteCommandParameterRegister(HostAdapter, *ParameterPointer++); ParameterLength--; } if (TimeoutCounter < 0) { BusLogic_CommandFailureReason = "Timeout waiting for Parameter Acceptance"; Result = -2; goto Done; } /* The Modify I/O Address command does not cause a Command Complete Interrupt. */ if (OperationCode == BusLogic_ModifyIOAddress) { StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); if (StatusRegister.sr.CommandInvalid) { BusLogic_CommandFailureReason = "Modify I/O Address Invalid"; Result = -1; goto Done; } if (BusLogic_GlobalOptions.TraceConfiguration) BusLogic_Notice("BusLogic_Command(%02X) Status = %02X: " "(Modify I/O Address)\n", HostAdapter, OperationCode, StatusRegister.All); Result = 0; goto Done; } /* Select an appropriate timeout value for awaiting command completion. */ switch (OperationCode) { case BusLogic_InquireInstalledDevicesID0to7: case BusLogic_InquireInstalledDevicesID8to15: case BusLogic_InquireTargetDevices: /* Approximately 60 seconds. */ TimeoutCounter = 60 * 10000; break; default: /* Approximately 1 second. */ TimeoutCounter = 10000; break; } /* Receive any Reply Bytes, waiting for either the Command Complete bit to be set in the Interrupt Register, or for the Interrupt Handler to set the Host Adapter Command Completed bit in the Host Adapter structure. */ while (--TimeoutCounter >= 0) { InterruptRegister.All = BusLogic_ReadInterruptRegister(HostAdapter); StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); if (InterruptRegister.ir.CommandComplete) break; if (HostAdapter->HostAdapterCommandCompleted) break; if (StatusRegister.sr.DataInRegisterReady) { if (++ReplyBytes <= ReplyLength) *ReplyPointer++ = BusLogic_ReadDataInRegister(HostAdapter); else BusLogic_ReadDataInRegister(HostAdapter); } if (OperationCode == BusLogic_FetchHostAdapterLocalRAM && StatusRegister.sr.HostAdapterReady) break; udelay(100); } if (TimeoutCounter < 0) { BusLogic_CommandFailureReason = "Timeout waiting for Command Complete"; Result = -2; goto Done; } /* Clear any pending Command Complete Interrupt. */ BusLogic_InterruptReset(HostAdapter); /* Provide tracing information if requested. */ if (BusLogic_GlobalOptions.TraceConfiguration) { int i; BusLogic_Notice("BusLogic_Command(%02X) Status = %02X: %2d ==> %2d:", HostAdapter, OperationCode, StatusRegister.All, ReplyLength, ReplyBytes); if (ReplyLength > ReplyBytes) ReplyLength = ReplyBytes; for (i = 0; i < ReplyLength; i++) BusLogic_Notice(" %02X", HostAdapter, ((unsigned char *) ReplyData)[i]); BusLogic_Notice("\n", HostAdapter); } /* Process Command Invalid conditions. */ if (StatusRegister.sr.CommandInvalid) { /* Some early BusLogic Host Adapters may not recover properly from a Command Invalid condition, so if this appears to be the case, a Soft Reset is issued to the Host Adapter. Potentially invalid commands are never attempted after Mailbox Initialization is performed, so there should be no Host Adapter state lost by a Soft Reset in response to a Command Invalid condition. */ udelay(1000); StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); if (StatusRegister.sr.CommandInvalid || StatusRegister.sr.Reserved || StatusRegister.sr.DataInRegisterReady || StatusRegister.sr.CommandParameterRegisterBusy || !StatusRegister.sr.HostAdapterReady || !StatusRegister.sr.InitializationRequired || StatusRegister.sr.DiagnosticActive || StatusRegister.sr.DiagnosticFailure) { BusLogic_SoftReset(HostAdapter); udelay(1000); } BusLogic_CommandFailureReason = "Command Invalid"; Result = -1; goto Done; } /* Handle Excess Parameters Supplied conditions. */ if (ParameterLength > 0) { BusLogic_CommandFailureReason = "Excess Parameters Supplied"; Result = -1; goto Done; } /* Indicate the command completed successfully. */ BusLogic_CommandFailureReason = NULL; Result = ReplyBytes; /* Restore the interrupt status if necessary and return. */ Done: if (!HostAdapter->IRQ_ChannelAcquired) local_irq_restore(ProcessorFlags); return Result;}/* BusLogic_AppendProbeAddressISA appends a single ISA I/O Address to the list of I/O Address and Bus Probe Information to be checked for potential BusLogic Host Adapters.*/static void __init BusLogic_AppendProbeAddressISA(unsigned long IO_Address){ struct BusLogic_ProbeInfo *ProbeInfo; if (BusLogic_ProbeInfoCount >= BusLogic_MaxHostAdapters) return; ProbeInfo = &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++]; ProbeInfo->HostAdapterType = BusLogic_MultiMaster; ProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus; ProbeInfo->IO_Address = IO_Address; ProbeInfo->PCI_Device = NULL;}/* BusLogic_InitializeProbeInfoListISA initializes the list of I/O Address and Bus Probe Information to be checked for potential BusLogic SCSI Host Adapters only from the list of standard BusLogic MultiMaster ISA I/O Addresses.*/static void __init BusLogic_InitializeProbeInfoListISA(struct BusLogic_HostAdapter *PrototypeHostAdapter){ /* If BusLogic Driver Options specifications requested that ISA Bus Probes be inhibited, do not proceed further. */ if (BusLogic_ProbeOptions.NoProbeISA) return; /* Append the list of standard BusLogic MultiMaster ISA I/O Addresses. */ if (!BusLogic_ProbeOptions.LimitedProbeISA || BusLogic_ProbeOptions.Probe330) BusLogic_AppendProbeAddressISA(0x330); if (!BusLogic_ProbeOptions.LimitedProbeISA || BusLogic_ProbeOptions.Probe334) BusLogic_AppendProbeAddressISA(0x334); if (!BusLogic_ProbeOptions.LimitedProbeISA || BusLogic_ProbeOptions.Probe230) BusLogic_AppendProbeAddressISA(0x230); if (!BusLogic_ProbeOptions.LimitedProbeISA || BusLogic_ProbeOptions.Probe234) BusLogic_AppendProbeAddressISA(0x234); if (!BusLogic_ProbeOptions.LimitedProbeISA || BusLogic_ProbeOptions.Probe130) BusLogic_AppendProbeAddressISA(0x130); if (!BusLogic_ProbeOptions.LimitedProbeISA || BusLogic_ProbeOptions.Probe134) BusLogic_AppendProbeAddressISA(0x134);}#ifdef CONFIG_PCI/* BusLogic_SortProbeInfo sorts a section of BusLogic_ProbeInfoList in order of increasing PCI Bus and Device Number.*/static void __init BusLogic_SortProbeInfo(struct BusLogic_ProbeInfo *ProbeInfoList, int ProbeInfoCount){ int LastInterchange = ProbeInfoCount - 1, Bound, j; while (LastInterchange > 0) { Bound = LastInterchange; LastInterchange = 0; for (j = 0; j < Bound; j++) { struct BusLogic_ProbeInfo *ProbeInfo1 = &ProbeInfoList[j]; struct BusLogic_ProbeInfo *ProbeInfo2 = &ProbeInfoList[j + 1]; if (ProbeInfo1->Bus > ProbeInfo2->Bus || (ProbeInfo1->Bus == ProbeInfo2->Bus && (ProbeInfo1->Device > ProbeInfo2->Device))) { struct BusLogic_ProbeInfo TempProbeInfo; memcpy(&TempProbeInfo, ProbeInfo1, sizeof(struct BusLogic_ProbeInfo)); memcpy(ProbeInfo1, ProbeInfo2, sizeof(struct BusLogic_ProbeInfo)); memcpy(ProbeInfo2, &TempProbeInfo, sizeof(struct BusLogic_ProbeInfo)); LastInterchange = j; } } }}/* BusLogic_InitializeMultiMasterProbeInfo initializes the list of I/O Address and Bus Probe Information to be checked for potential BusLogic MultiMaster SCSI Host Adapters by interrogating the PCI Configuration Space on PCI machines as well as from the list of standard BusLogic MultiMaster ISA I/O Addresses. It returns the number of PCI MultiMaster Host Adapters found.*/static int __init BusLogic_InitializeMultiMasterProbeInfo(struct BusLogic_HostAdapter *PrototypeHostAdapter){ struct BusLogic_ProbeInfo *PrimaryProbeInfo = &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount]; int NonPrimaryPCIMultiMasterIndex = BusLogic_ProbeInfoCount + 1; int NonPrimaryPCIMultiMasterCount = 0, PCIMultiMasterCount = 0; bool ForceBusDeviceScanningOrder = false; bool ForceBusDeviceScanningOrderChecked = false; bool StandardAddressSeen[6];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -