#include "Sym8xxController.h"
extern "C"
{
unsigned int ml_phys_read( vm_offset_t paddr );
};
#if 0
static UInt32 dropInt = 0;
#endif
void Sym8xxSCSIController::Sym8xxStartSRB( SRB *srb )
{
srb->nexus.targetParms.scntl3Reg = adapter->targetClocks[srb->target].scntl3Reg;
srb->nexus.targetParms.sxferReg = adapter->targetClocks[srb->target].sxferReg;
adapter->nexusPtrsVirt[srb->nexus.tag] = &srb->nexus;
adapter->nexusPtrsPhys[srb->nexus.tag] = (Nexus *)OSSwapHostToLittleInt32( (UInt32)&srb->srbPhys->nexus );
adapter->schedMailBox[mailBoxIndex++] = (Nexus *)OSSwapHostToLittleInt32 ( (UInt32)&srb->srbPhys->nexus );
Sym8xxSignalScript( srb );
}
void Sym8xxSCSIController::interruptOccurred( IOInterruptEventSource *ies, int intCount )
{
do
{
istatReg = Sym8xxReadRegs( chipBaseAddr, ISTAT, ISTAT_SIZE );
if ( istatReg & INTF )
{
Sym8xxWriteRegs( chipBaseAddr, ISTAT, ISTAT_SIZE, istatReg );
#if 0
if ( dropInt++ > 100 )
{
dropInt = 0;
SCRIPT_VAR(R_ld_IOdone_mailbox) = 0;
continue;
}
#endif
Sym8xxProcessIODone();
}
if ( istatReg & (SIP | DIP) )
{
Sym8xxProcessInterrupt();
}
}
while ( istatReg & (SIP | DIP | INTF) );
getWorkLoop()->enableAllInterrupts();
}
void Sym8xxSCSIController::Sym8xxProcessIODone()
{
SRB *srb;
Nexus *nexus;
IODoneMailBox *pMailBox;
pMailBox = (IODoneMailBox *)&SCRIPT_VAR(R_ld_IOdone_mailbox);
nexus = adapter->nexusPtrsVirt[pMailBox->nexus];
srb = (SRB *)((UInt32)nexus - offsetof(SRB, nexus));
srb->srbSCSIStatus = pMailBox->status;
if ( srb->srbSCSIStatus == kSCSIStatusCheckCondition )
{
Sym8xxCheckRequestSense( srb );
}
Sym8xxUpdateXferOffset( srb );
adapter->nexusPtrsVirt[pMailBox->nexus] = (Nexus *) -1;
adapter->nexusPtrsPhys[pMailBox->nexus] = (Nexus *) -1;
SCRIPT_VAR(R_ld_IOdone_mailbox) = 0;
Sym8xxCompleteSRB( srb );
scriptRestartAddr = (UInt32) &chipRamAddrPhys[Ent_select_phase];
}
void Sym8xxSCSIController::Sym8xxCompleteSRB( SRB *srb )
{
IOSCSIParallelCommand *scsiCommand;
SCSIResults scsiResults;
SCSINegotiationResults negotiationResult, *negResult;
scsiCommand = srb->scsiCommand;
bzero( &scsiResults, sizeof(scsiResults) );
scsiResults.adapterStatus = srb->srbAdapterStatus;
scsiResults.returnCode = srb->srbReturnCode;
if ( srb == abortSRB )
{
abortSRB = 0;
if ( abortReqPending == true )
{
abortReqPending = false;
enableCommands();
}
}
else
{
scsiResults.bytesTransferred = srb->xferDone;
scsiResults.scsiStatus = srb->srbSCSIStatus;
}
negResult = 0;
if ( (srb->srbCDBFlags & kCDBFlagsNegotiateSDTR) || (srb->srbCDBFlags & kCDBFlagsNegotiateWDTR) )
{
bzero( &negotiationResult, sizeof(struct SCSINegotiationResults) );
if ( ((srb->srbCDBFlags & kCDBFlagsNegotiateSDTR) && srb->negotiateSDTRComplete == false) ||
((srb->srbCDBFlags & kCDBFlagsNegotiateWDTR) && srb->negotiateWDTRComplete == false) )
{
negotiationResult.returnCode = kIOReturnIOError;
}
negotiationResult.transferPeriodpS = transferPeriod;
negotiationResult.transferOffset = transferOffset;
negotiationResult.transferWidth = transferWidth;
negotiationResult.transferOptions = 0;
negResult = &negotiationResult;
}
scsiCommand->setResults( &scsiResults, negResult );
if ( srb->srbIOMD ) (srb->srbIOMD)->complete();
scsiCommand->complete();
}
void Sym8xxSCSIController::Sym8xxProcessInterrupt()
{
SRB *srb = NULL;
Nexus *nexus = NULL;
UInt32 nexusIndex;
UInt32 scriptPhase;
UInt32 fifoCnt = 0;
UInt32 dspsReg = 0;
UInt32 dspReg = 0;
dstatReg = Sym8xxReadRegs( chipBaseAddr, DSTAT, DSTAT_SIZE );
IODelay(5);
sistReg = Sym8xxReadRegs( chipBaseAddr, SIST, SIST_SIZE );
scriptPhase = OSSwapHostToLittleInt32( SCRIPT_VAR(R_ld_phase_flag) );
if ( sistReg & RSTI )
{
Sym8xxProcessSCSIBusReset();
return;
}
nexusIndex = OSSwapHostToLittleInt32(SCRIPT_VAR(R_ld_nexus_index));
if ( nexusIndex >= MAX_SCSI_TAG )
{
Sym8xxProcessNoNexus();
return;
}
nexus = adapter->nexusPtrsVirt[nexusIndex];
if ( nexus == (Nexus *) -1 )
{
Sym8xxProcessNoNexus();
return;
}
srb = (SRB *)((UInt32)nexus - offsetof(SRB, nexus));
scriptRestartAddr = (UInt32) &chipRamAddrPhys[Ent_phase_handler];
if ( sistReg & PAR )
{
srb->srbAdapterStatus = kSCSIAdapterStatusParityError;
Sym8xxAbortCurrent( srb );
}
else if ( sistReg & SGE )
{
srb->srbAdapterStatus = kSCSIAdapterStatusProtocolError;
Sym8xxAbortCurrent( srb );
}
else if ( sistReg & UDC )
{
if ( srb->srbAdapterStatus == kSCSIAdapterStatusSuccess )
{
srb->srbAdapterStatus = kSCSIAdapterStatusProtocolError;
}
adapter->nexusPtrsVirt[nexusIndex] = (Nexus *) -1;
adapter->nexusPtrsPhys[nexusIndex] = (Nexus *) -1;
if ( scriptPhase == A_kphase_ABORT_CURRENT )
{
abortCurrentSRB = NULL;
}
Sym8xxCompleteSRB( srb );
scriptRestartAddr = (UInt32) &chipRamAddrPhys[Ent_select_phase];
}
else if ( sistReg & MA )
{
if ( scriptPhase == A_kphase_MSG_OUT )
{
srb->srbMsgResid = Sym8xxCheckFifo( srb, &fifoCnt );
nexus->msg.ppData = OSSwapHostToLittleInt32( OSSwapHostToLittleInt32(nexus->msg.ppData)
+ OSSwapHostToLittleInt32(nexus->msg.length)
- srb->srbMsgResid );
nexus->msg.length = OSSwapHostToLittleInt32( srb->srbMsgResid );
Sym8xxAbortCurrent( srb );
}
else if ( (scriptPhase == A_kphase_DATA_OUT) || (scriptPhase == A_kphase_DATA_IN) )
{
Sym8xxAdjustDataPtrs( srb, nexus );
}
else
{
IOLog("SCSI(Symbios8xx): Unexpected phase mismatch - scriptPhase = %08x\n\r", (int)scriptPhase);
Sym8xxAbortCurrent( srb );
}
Sym8xxClearFifo();
}
else if ( sistReg & STO )
{
srb->srbAdapterStatus = kSCSIAdapterStatusSelectionTimeout;
adapter->nexusPtrsVirt[nexusIndex] = (Nexus *) -1;
adapter->nexusPtrsPhys[nexusIndex] = (Nexus *) -1;
SCRIPT_VAR(R_ld_IOdone_mailbox) = 0;
Sym8xxCompleteSRB( srb );
scriptRestartAddr = (UInt32) &chipRamAddrPhys[Ent_select_phase];
}
else if ( dstatReg & SIR )
{
dspsReg = Sym8xxReadRegs( chipBaseAddr, DSPS, DSPS_SIZE );
switch ( dspsReg )
{
case A_status_error:
Sym8xxProcessIODone();
break;
case A_negotiateSDTR:
Sym8xxNegotiateSDTR( srb, nexus );
break;
case A_negotiateWDTR:
Sym8xxNegotiateWDTR( srb, nexus );
break;
case A_sglist_complete:
Sym8xxUpdateSGList( srb );
scriptRestartAddr = (UInt32)&srb->srbPhys->nexus.sgListData[2];
break;
case A_abort_current:
adapter->nexusPtrsVirt[nexusIndex] = (Nexus *) -1;
adapter->nexusPtrsPhys[nexusIndex] = (Nexus *) -1;
abortCurrentSRB = NULL;
Sym8xxCompleteSRB( srb );
scriptRestartAddr = (UInt32) &chipRamAddrPhys[Ent_select_phase];
break;
case A_unknown_phase:
srb->srbAdapterStatus = kSCSIAdapterStatusProtocolError;
Sym8xxAbortCurrent( srb );
break;
case A_unknown_msg_reject:
case A_unexpected_msg:
case A_unexpected_ext_msg:
srb->srbAdapterStatus = kSCSIAdapterStatusMsgReject;
Sym8xxAbortCurrent( srb );
break;
default:
IOLog( "SCSI(Symbios8xx): Unknown Script Int = %08x\n\r", (int)dspsReg );
Sym8xxAbortCurrent( srb );
}
}
else if ( dstatReg & IID )
{
dspReg = Sym8xxReadRegs( chipBaseAddr, DSP, DSP_SIZE );
IOLog("SCSI(Symbios8xx): Illegal script instruction - dsp = %08x srb=%08x\n\r", (int)dspReg, (int)srb );
Sym8xxAbortCurrent( srb );
}
if ( scriptRestartAddr )
{
Sym8xxWriteRegs( chipBaseAddr, DSP, DSP_SIZE, scriptRestartAddr );
}
}
void Sym8xxSCSIController::Sym8xxAdjustDataPtrs( SRB *srb, Nexus *nexus )
{
UInt32 i;
UInt32 sgResid;
UInt32 fifoCnt;
UInt32 dspReg;
UInt32 sgDone;
UInt8 scntl2Reg;
Nexus *nexusPhys;
sgResid = Sym8xxCheckFifo( srb, &fifoCnt );
dspReg = Sym8xxReadRegs( chipBaseAddr, DSP, DSP_SIZE );
i = ((dspReg - (UInt32)srb->srbPhys->nexus.sgListData) / sizeof(SGEntry)) - 1;
if ( i > MAX_SGLIST_ENTRIES-1 )
{
IOLog("SCSI(Symbios8xx): Bad sgListIndex\n\r");
Sym8xxAbortCurrent( srb );
return;
}
nexusPhys = &srb->srbPhys->nexus;
scntl2Reg = Sym8xxReadRegs( chipBaseAddr, SCNTL2, SCNTL2_SIZE );
if ( scntl2Reg & WSR )
{
adapter->xferSWideInst[0] = OSSwapHostToLittleInt32( srb->directionMask | 1 );
adapter->xferSWideInst[1] = nexus->sgListData[i].physAddr;
adapter->xferSWideInst[2] = OSSwapHostToLittleInt32( 0x80080000 );
adapter->xferSWideInst[3] = OSSwapHostToLittleInt32( (UInt32)&chipRamAddrPhys[Ent_phase_handler] );
scriptRestartAddr = (UInt32) adapterPhys->xferSWideInst;
sgResid--;
}
sgDone = (OSSwapHostToLittleInt32( nexus->sgListData[i].length ) & 0x00ffffff) - sgResid;
nexus->sgListData[0].length = OSSwapHostToLittleInt32( sgResid | srb->directionMask );
nexus->sgListData[0].physAddr = OSSwapHostToLittleInt32( OSSwapHostToLittleInt32(nexus->sgListData[i].physAddr) + sgDone );
if ( i != 0 )
{
nexus->sgListData[1].length = OSSwapHostToLittleInt32( 0x80080000 );
nexus->sgListData[1].physAddr = OSSwapHostToLittleInt32( (UInt32)&nexusPhys->sgListData[i+1] );
nexus->sgNextIndex = i + 1;
}
nexus->ppSGList = (SGEntry *)OSSwapHostToLittleInt32( (UInt32) &nexusPhys->sgListData[0] );
nexus->dataXferCalled = 0;
return;
}
UInt32 Sym8xxSCSIController::Sym8xxCheckFifo( SRB *srb, UInt32 *pfifoCnt )
{
bool fSCSISend;
bool fXferSync;
UInt32 scriptPhase = 0;
UInt32 dbcReg = 0;
UInt32 dfifoReg = 0;
UInt32 ctest5Reg = 0;
UInt8 sstat0Reg = 0;
UInt8 sstat1Reg = 0;
UInt8 sstat2Reg = 0;
UInt32 fifoCnt = 0;
UInt32 sgResid = 0;
scriptPhase = OSSwapHostToLittleInt32( SCRIPT_VAR(R_ld_phase_flag) );
fSCSISend = (scriptPhase == A_kphase_DATA_OUT) || (scriptPhase == A_kphase_MSG_OUT);
fXferSync = ((scriptPhase == A_kphase_DATA_OUT) || (scriptPhase == A_kphase_DATA_IN))
&& (srb->nexus.targetParms.sxferReg & 0x1F);
dbcReg = Sym8xxReadRegs( chipBaseAddr, DBC, DBC_SIZE ) & 0x00ffffff;
if ( !(dstatReg & DFE) )
{
ctest5Reg = Sym8xxReadRegs( chipBaseAddr, CTEST5, CTEST5_SIZE );
dfifoReg = Sym8xxReadRegs( chipBaseAddr, DFIFO, DFIFO_SIZE );
if ( ctest5Reg & DFS )
{
fifoCnt = ((((ctest5Reg & 0x03) << 8) | dfifoReg) - dbcReg) & 0x3ff;
}
else
{
fifoCnt = (dfifoReg - dbcReg) & 0x7f;
}
}
sstat0Reg = Sym8xxReadRegs( chipBaseAddr, SSTAT0, SSTAT0_SIZE );
sstat2Reg = Sym8xxReadRegs( chipBaseAddr, SSTAT2, SSTAT2_SIZE );
if ( fSCSISend )
{
fifoCnt += (sstat0Reg & OLF ) ? 1 : 0;
fifoCnt += (sstat2Reg & OLF1) ? 1 : 0;
if ( fXferSync )
{
fifoCnt += (sstat0Reg & ORF ) ? 1 : 0;
fifoCnt += (sstat2Reg & ORF1) ? 1 : 0;
}
}
else
{
if ( fXferSync )
{
sstat1Reg = Sym8xxReadRegs( chipBaseAddr, SSTAT0, SSTAT0_SIZE );
fifoCnt += (sstat1Reg >> 4) | (sstat2Reg & FF4);
}
else
{
fifoCnt += (sstat0Reg & ILF ) ? 1 : 0;
fifoCnt += (sstat2Reg & ILF1) ? 1 : 0;
}
}
sgResid = dbcReg + fifoCnt;
*pfifoCnt = fifoCnt;
return sgResid;
}
void Sym8xxSCSIController::Sym8xxUpdateXferOffset( SRB *srb )
{
UInt32 i;
UInt32 xferOffset;
xferOffset = srb->xferOffset;
if ( srb->nexus.dataXferCalled == 0 )
{
xferOffset = srb->xferOffsetPrev;
if ( srb->nexus.sgNextIndex != 0 )
{
xferOffset += OSSwapHostToLittleInt32( srb->nexus.sgListData[srb->nexus.sgNextIndex-1].length )
- OSSwapHostToLittleInt32( srb->nexus.sgListData[0].length );
for ( i=2; i < srb->nexus.sgNextIndex-1; i++ )
{
xferOffset += OSSwapHostToLittleInt32( srb->nexus.sgListData[i].length ) & 0x00ffffff;
}
}
}
xferOffset -= srb->nexus.wideResidCount;
#if 0
{
UInt32 resid = srb->xferOffset - xferOffset;
if ( resid )
{
IOLog( "SCSI(Symbios8xx): Incomplete transfer - Req Count = %08x Act Count = %08x - srb = %08x\n\r",
srb->xferCount, xferOffset, (UInt32)srb );
}
}
#endif
srb->xferDone = xferOffset;
}
void Sym8xxSCSIController::Sym8xxProcessNoNexus()
{
UInt32 dspsReg;
UInt32 dspReg = 0;
UInt32 scriptPhase = (UInt32)-1 ;
scriptRestartAddr = (UInt32) &chipRamAddrPhys[Ent_select_phase];
dspsReg = Sym8xxReadRegs( chipBaseAddr, DSPS, DSPS_SIZE );
scriptPhase = OSSwapHostToLittleInt32( SCRIPT_VAR(R_ld_phase_flag) );
if ( sistReg & UDC )
{
if ( (scriptPhase == A_kphase_ABORT_MAILBOX) && abortSRB )
{
Sym8xxCompleteSRB( abortSRB );
SCRIPT_VAR(R_ld_AbortBdr_mailbox) = 0;
}
else if ( scriptPhase == A_kphase_ABORT_CURRENT )
{
abortCurrentSRB = NULL;
}
}
else if ( sistReg & STO )
{
if ( (scriptPhase == A_kphase_ABORT_MAILBOX) && abortSRB )
{
Sym8xxCompleteSRB( abortSRB );
SCRIPT_VAR(R_ld_AbortBdr_mailbox) = 0;
}
}
else if ( dstatReg & IID )
{
dspReg = Sym8xxReadRegs( chipBaseAddr, DSP, DSP_SIZE );
IOLog("SCSI(Symbios8xx): Illegal script instruction - dsp = %08x srb=0\n\r", (int)dspReg );
Sym8xxAbortCurrent( (SRB *)-1 );
}
else if ( dstatReg & SIR )
{
switch ( dspsReg )
{
case A_abort_current:
abortCurrentSRB = NULL;
break;
case A_abort_mailbox:
Sym8xxCompleteSRB( abortSRB );
SCRIPT_VAR(R_ld_AbortBdr_mailbox) = 0;
break;
default:
Sym8xxAbortCurrent( (SRB *)-1 );
}
}
else
{
Sym8xxAbortCurrent( (SRB *)-1 );
}
if ( scriptRestartAddr )
{
Sym8xxWriteRegs( chipBaseAddr, DSP, DSP_SIZE, scriptRestartAddr );
}
}
void Sym8xxSCSIController::Sym8xxAbortCurrent( SRB *srb )
{
if ( abortCurrentSRB )
{
if ( abortCurrentSRB != srb )
{
IOLog("SCSI(Symbios8xx): Multiple abort immediate SRBs - resetting\n\r");
Sym8xxSCSIBusReset( (SRB *)0 );
}
return;
}
abortCurrentSRB = srb;
if ( srb != (SRB *)-1 )
{
if ( srb->srbAdapterStatus == kSCSIAdapterStatusSuccess )
{
srb->srbAdapterStatus = kSCSIAdapterStatusProtocolError;
}
}
SCRIPT_VAR(R_ld_AbortCode) = OSSwapHostToLittleInt32( ((srb != (SRB *)-1) && (srb->nexus.tag >= MIN_SCSI_TAG)) ? 0x0d : 0x06 );
scriptRestartAddr = (UInt32) &chipRamAddrPhys[Ent_issueAbort_BDR];
Sym8xxClearFifo();
}
void Sym8xxSCSIController::Sym8xxClearFifo()
{
UInt8 ctest3Reg;
UInt8 stest2Reg;
UInt8 stest3Reg;
stest2Reg = Sym8xxReadRegs( chipBaseAddr, STEST2, STEST2_SIZE );
if ( stest2Reg & ROF )
{
Sym8xxWriteRegs( chipBaseAddr, STEST2, STEST2_SIZE, stest2Reg );
}
ctest3Reg = Sym8xxReadRegs( chipBaseAddr, CTEST3, CTEST3_SIZE );
ctest3Reg |= CLF;
Sym8xxWriteRegs( chipBaseAddr, CTEST3, CTEST3_SIZE, ctest3Reg );
stest3Reg = Sym8xxReadRegs( chipBaseAddr, STEST3, STEST3_SIZE );
stest3Reg |= CSF;
Sym8xxWriteRegs( chipBaseAddr,STEST3, STEST3_SIZE, stest3Reg );
do
{
ctest3Reg = Sym8xxReadRegs( chipBaseAddr, CTEST3, CTEST3_SIZE );
stest2Reg = Sym8xxReadRegs( chipBaseAddr, STEST3, STEST3_SIZE );
stest3Reg = Sym8xxReadRegs( chipBaseAddr, STEST3, STEST3_SIZE );
}
while( (ctest3Reg & CLF) || (stest3Reg & CSF) || (stest2Reg & ROF) );
}
void Sym8xxSCSIController::Sym8xxNegotiateSDTR( SRB *srb, Nexus *nexus )
{
UInt32 x;
UInt8 *pMsg;
UInt32 syncPeriod;
if ( !(srb->srbCDBFlags & kCDBFlagsNegotiateSDTR) )
{
Sym8xxSendMsgReject( srb );
return;
}
pMsg = (UInt8 *) &SCRIPT_VAR(R_ld_message);
if ( pMsg[4] == 0 )
{
nexus->targetParms.scntl3Reg &= 0x0f;
nexus->targetParms.sxferReg = 0x00;
}
else
{
syncPeriod = (UInt32)pMsg[3] << 2;
if ( syncPeriod < 100 )
{
nexus->targetParms.scntl3Reg |= SCNTL3_INIT_875_ULTRA;
x = (syncPeriod * 1000) / 125;
}
else if ( syncPeriod < 200 )
{
nexus->targetParms.scntl3Reg |= SCNTL3_INIT_875_FAST;
x = (syncPeriod * 1000) / 250;
}
else
{
nexus->targetParms.scntl3Reg |= SCNTL3_INIT_875_SLOW;
x = (syncPeriod * 1000) / 500;
}
if ( x % 100 ) x += 100;
nexus->targetParms.sxferReg = ((x/100 - 4) << 5) | pMsg[4];
transferPeriod = syncPeriod * 1000;
transferOffset = pMsg[4];
if ( ( srb->srbCDBFlags & kCDBFlagsNegotiateWDTR ) == 0 )
{
transferWidth = 1;
}
srb->negotiateSDTRComplete = true;
}
adapter->targetClocks[srb->target].sxferReg = nexus->targetParms.sxferReg;
adapter->targetClocks[srb->target].scntl3Reg = nexus->targetParms.scntl3Reg;
Sym8xxWriteRegs( chipBaseAddr, SCNTL3, SCNTL3_SIZE, nexus->targetParms.scntl3Reg );
Sym8xxWriteRegs( chipBaseAddr, SXFER, SXFER_SIZE, nexus->targetParms.sxferReg );
scriptRestartAddr = (UInt32) &chipRamAddrPhys[Ent_clearACK];
}
void Sym8xxSCSIController::Sym8xxNegotiateWDTR( SRB *srb, Nexus *nexus )
{
UInt8 *pMsg;
UInt32 msgBytesSent;
UInt32 msgBytesLeft;
if ( !(srb->srbCDBFlags & kCDBFlagsNegotiateWDTR) )
{
Sym8xxSendMsgReject( srb );
return;
}
pMsg = (UInt8 *) &SCRIPT_VAR(R_ld_message);
if ( pMsg[3] == 1 )
{
nexus->targetParms.scntl3Reg |= EWS;
transferWidth = 2;
}
else
{
nexus->targetParms.scntl3Reg &= ~EWS;
transferWidth = 1;
}
adapter->targetClocks[srb->target].scntl3Reg = nexus->targetParms.scntl3Reg;
Sym8xxWriteRegs( chipBaseAddr, SCNTL3, SCNTL3_SIZE, nexus->targetParms.scntl3Reg );
srb->negotiateWDTRComplete = true;
msgBytesSent = OSSwapHostToLittleInt32( nexus->msg.length );
msgBytesLeft = srb->srbMsgLength - msgBytesSent;
if ( msgBytesLeft )
{
nexus->msg.length = OSSwapHostToLittleInt32( msgBytesLeft );
nexus->msg.ppData = OSSwapHostToLittleInt32( OSSwapHostToLittleInt32( nexus->msg.ppData ) + msgBytesSent );
scriptRestartAddr = (UInt32) &chipRamAddrPhys[Ent_issueMessageOut];
}
else
{
scriptRestartAddr = (UInt32) &chipRamAddrPhys[Ent_clearACK];
}
}
void Sym8xxSCSIController::Sym8xxSendMsgReject( SRB *srb )
{
srb->nexus.msg.ppData = OSSwapHostToLittleInt32((UInt32)&srb->srbPhys->nexus.msgData);
srb->nexus.msg.length = OSSwapHostToLittleInt32(0x01);
srb->nexus.msgData[0] = 0x07;
scriptRestartAddr = (UInt32) &chipRamAddrPhys[Ent_issueMessageOut];
}
void Sym8xxSCSIController::Sym8xxSCSIBusReset( SRB *srb )
{
if ( srb )
{
if ( resetSRB )
{
srb->srbReturnCode = kIOReturnBusy;
Sym8xxCompleteSRB( srb );
return;
}
resetSRB = srb;
}
Sym8xxAbortScript();
Sym8xxWriteRegs( chipBaseAddr, SCNTL1, SCNTL1_SIZE, SCNTL1_SCSI_RST );
IODelay( 100 );
Sym8xxWriteRegs( chipBaseAddr, SCNTL1, SCNTL1_SIZE, SCNTL1_INIT );
}
void Sym8xxSCSIController::Sym8xxProcessSCSIBusReset()
{
UInt32 i;
Sym8xxClearFifo();
for ( i=0; i < MAX_SCHED_MAILBOXES; i++ )
{
adapter->schedMailBox[i] = 0;
}
SCRIPT_VAR(R_ld_AbortBdr_mailbox) = 0;
SCRIPT_VAR(R_ld_IOdone_mailbox) = 0;
SCRIPT_VAR(R_ld_counter) = 0;
mailBoxIndex = 0;
for ( i=0; i < MAX_SCSI_TARGETS; i++ )
{
adapter->targetClocks[i].scntl3Reg = SCNTL3_INIT_875;
adapter->targetClocks[i].sxferReg = 0;
}
scriptRestartAddr = (UInt32) &chipRamAddrPhys[Ent_select_phase];
Sym8xxWriteRegs( chipBaseAddr, DSP, DSP_SIZE, scriptRestartAddr );
if ( resetSRB )
{
resetSRB->srbReturnCode = kIOReturnBusy;
Sym8xxCompleteSRB( resetSRB );
resetSRB = 0;
}
else if ( initialReset == true )
{
initialReset = false;
}
else
{
resetOccurred();
}
}
void Sym8xxSCSIController::Sym8xxSignalScript( SRB *srb )
{
Sym8xxWriteRegs( chipBaseAddr, ISTAT, ISTAT_SIZE, SIGP );
}
void Sym8xxSCSIController::Sym8xxCheckRequestSense( SRB *srb )
{
IOSCSIParallelCommand *scsiCommand;
IOMemoryDescriptor *reqSenseDesc;
scsiCommand = srb->scsiCommand;
scsiCommand->getPointers( &reqSenseDesc, 0, 0, true );
if ( reqSenseDesc != 0 )
{
Sym8xxCancelMailBox( srb->target, srb->lun, true );
}
}
void Sym8xxSCSIController::Sym8xxAbortBdr( SRB *srb )
{
IOAbortBdrMailBox abortMailBox;
abortSRB = srb;
abortMailBox.identify = srb->nexus.msgData[0];
abortMailBox.tag = srb->nexus.msgData[1];
abortMailBox.message = srb->nexus.msgData[2];
abortMailBox.scsi_id = srb->target;
SCRIPT_VAR(R_ld_AbortBdr_mailbox) = *(UInt32 *) &abortMailBox;
Sym8xxSignalScript( srb );
}
bool Sym8xxSCSIController::Sym8xxCancelMailBox( Nexus *nexusCancel )
{
Nexus *nexusPhys;
UInt32 i;
nexusPhys = (Nexus *)OSSwapHostToLittleInt32( (UInt32)nexusCancel );
for ( i=0; i < MAX_SCHED_MAILBOXES; i++ )
{
if ( nexusPhys == adapter->schedMailBox[i] )
{
adapter->schedMailBox[i] = (Nexus *)OSSwapHostToLittleInt32( kMailBoxCancel );
return true;
}
}
return false;
}
void Sym8xxSCSIController::Sym8xxCancelMailBox( UInt32 target, UInt32 lun, bool fReschedule )
{
UInt32 i, j;
SRB *srb;
Nexus *nexus;
Nexus *nexusPhys;
for ( i=0; i < MAX_SCHED_MAILBOXES; i++ )
{
nexusPhys = (Nexus *)OSSwapHostToLittleInt32( (UInt32)adapter->schedMailBox[i] );
if ( (nexusPhys != (Nexus *)kMailBoxEmpty) && (nexusPhys != (Nexus *)kMailBoxCancel) )
{
for ( nexus = (Nexus *)-1, j = 0; j < MAX_SCHED_MAILBOXES; j++ )
{
if ( adapter->nexusPtrsPhys[j] == nexusPhys )
{
nexus = adapter->nexusPtrsVirt[j];
break;
}
}
if ( nexus == (Nexus *)-1 )
{
continue;
}
srb = (SRB *)((UInt32)nexus - offsetof(SRB, nexus));
if ( srb->target == target )
{
if ( (lun == (UInt32)-1) || (srb->lun == lun) )
{
adapter->schedMailBox[i] = (Nexus *)OSSwapHostToLittleInt32( kMailBoxCancel );
if ( fReschedule == true )
{
rescheduleCommand( srb->scsiCommand );
}
}
}
}
}
}
void Sym8xxSCSIController::Sym8xxAbortScript()
{
mach_timespec_t currentTime;
mach_timespec_t startTime;
getWorkLoop()->disableAllInterrupts();
Sym8xxWriteRegs( chipBaseAddr, ISTAT, ISTAT_SIZE, ABRT );
IOGetTime( &startTime );
do
{
IOGetTime( ¤tTime );
SUB_MACH_TIMESPEC( ¤tTime, &startTime );
istatReg = Sym8xxReadRegs( chipBaseAddr, ISTAT, ISTAT_SIZE );
if ( istatReg & SIP )
{
Sym8xxReadRegs( chipBaseAddr, SIST, SIST_SIZE );
continue;
}
if ( istatReg & DIP )
{
Sym8xxWriteRegs( chipBaseAddr, ISTAT, ISTAT_SIZE, 0x00 );
Sym8xxReadRegs( chipBaseAddr, DSTAT, DSTAT_SIZE );
break;
}
}
while ( currentTime.tv_nsec < (kAbortScriptTimeoutMS * 1000 * 1000) );
istatReg = SIGP;
Sym8xxWriteRegs( chipBaseAddr, ISTAT, ISTAT_SIZE, istatReg );
getWorkLoop()->enableAllInterrupts();
if ( currentTime.tv_nsec >= (kAbortScriptTimeoutMS * 1000 * 1000) )
{
IOLog( "SCSI(Symbios8xx): Abort script failed - resetting bus\n\r" );
}
}