#include "Sym8xxController.h"
extern pmap_t kernel_pmap;
void Sym8xxSCSIController::executeCommand( IOSCSIParallelCommand *scsiCommand )
{
SRB *srb = NULL;
SCSICDBInfo scsiCDB;
SCSITargetLun targetLun;
Nexus *nexus;
Nexus *nexusPhys;
UInt32 len;
bool isWrite;
srb = (SRB *) scsiCommand->getCommandData();
bzero( srb, sizeof(SRB) );
srb->srbPhys = (SRB *) pmap_extract( kernel_pmap, (vm_offset_t) srb );
srb->scsiCommand = scsiCommand;
scsiCommand->getCDB( &scsiCDB );
scsiCommand->getTargetLun( &targetLun );
nexus = &srb->nexus;
nexusPhys = &srb->srbPhys->nexus;
srb->target = targetLun.target;
srb->lun = targetLun.lun;
srb->srbCDBFlags = scsiCDB.cdbFlags;
nexus->targetParms.target = srb->target;
switch ( scsiCommand->getCmdType() )
{
case kSCSICommandAbort:
case kSCSICommandAbortAll:
case kSCSICommandDeviceReset:
Sym8xxAbortCommand( scsiCommand );
return;
default:
;
}
scsiCommand->getPointers( &srb->xferDesc, &srb->xferCount, &isWrite );
srb->directionMask = (isWrite) ? 0x00000000 :0x01000000;
nexus->cdb.ppData = OSSwapHostToLittleInt32((UInt32)&nexusPhys->cdbData);
len = scsiCDB.cdbLength;
nexus->cdb.length = OSSwapHostToLittleInt32( len );
nexus->cdbData = scsiCDB.cdb;
Sym8xxCalcMsgs( scsiCommand );
nexus->ppSGList = (SGEntry *)OSSwapHostToLittleInt32((UInt32)&nexusPhys->sgListData[2]);
Sym8xxUpdateSGList( srb );
Sym8xxStartSRB( srb );
}
void Sym8xxSCSIController::resetCommand( IOSCSIParallelCommand *scsiCommand )
{
SRB *srb;
srb = (SRB *) scsiCommand->getCommandData();
bzero( srb, sizeof(SRB) );
srb->srbPhys = (SRB *) pmap_extract( kernel_pmap, (vm_offset_t) srb );
srb->scsiCommand = scsiCommand;
Sym8xxSCSIBusReset( srb );
}
void Sym8xxSCSIController::cancelCommand( IOSCSIParallelCommand *scsiCommand )
{
IOSCSIParallelCommand *origCommand;
SRB *srb;
SCSITargetLun targetLun;
SCSIResults scsiResults;
origCommand = scsiCommand->getOriginalCmd();
srb = (SRB *)origCommand->getCommandData();
switch ( origCommand->getCmdType() )
{
case kSCSICommandAbort:
case kSCSICommandAbortAll:
case kSCSICommandDeviceReset:
if ( abortSRB == srb )
{
SCRIPT_VAR(R_ld_AbortBdr_mailbox) = 0;
abortSRB = 0;
origCommand->complete();
}
break;
default:
if ( adapter->nexusPtrsVirt[srb->nexus.tag] == &srb->nexus )
{
adapter->nexusPtrsVirt[srb->nexus.tag] = (Nexus *) -1;
adapter->nexusPtrsPhys[srb->nexus.tag] = (Nexus *) -1;
origCommand->complete();
}
else
{
origCommand->getTargetLun( &targetLun );
origCommand->complete();
IOLog( "SCSI(Symbios8xx): Aborted SRB not found - T/L = %d:%d\n\r", targetLun.target, targetLun.lun );
}
}
bzero( &scsiResults, sizeof(scsiResults) );
scsiCommand->setResults( &scsiResults );
scsiCommand->complete();
}
void Sym8xxSCSIController::Sym8xxAbortCommand( IOSCSIParallelCommand *scsiCommand )
{
SRB *srb;
SCSICDBInfo scsiCDB;
SCSITargetLun targetLun;
scsiCommand->getTargetLun( &targetLun );
switch ( scsiCommand->getCmdType() )
{
case kSCSICommandAbort:
srb = (SRB *)scsiCommand->getOriginalCmd()->getCommandData();
Sym8xxCancelMailBox( &srb->srbPhys->nexus );
break;
case kSCSICommandAbortAll:
Sym8xxCancelMailBox( targetLun.target, targetLun.lun, false );
break;
case kSCSICommandDeviceReset:
Sym8xxCancelMailBox( targetLun.target, (UInt32) -1, false );
break;
default:
;
}
if ( abortSRB )
{
abortReqPending = true;
rescheduleCommand( scsiCommand );
disableCommands();
return;
}
scsiCommand->getCDB( &scsiCDB );
srb = (SRB *) scsiCommand->getCommandData();
srb->nexus.msgData[0] = srb->lun | ((srb->srbCDBFlags & kCDBFlagsNoDisconnect ) ? 0x80 : 0xC0);
if ( scsiCDB.cdbTagMsg != 0 )
{
srb->nexus.tag = scsiCDB.cdbTag + 128;
srb->nexus.msgData[1] = srb->nexus.tag;
}
else
{
srb->nexus.tag = ((UInt32)srb->target << 3) | srb->lun;
srb->nexus.msgData[1] = 0;
}
srb->tag = srb->nexus.tag;
srb->nexus.msgData[2] = scsiCDB.cdbAbortMsg;
Sym8xxAbortBdr( srb );
}
void Sym8xxSCSIController::Sym8xxCalcMsgs( IOSCSIParallelCommand *scsiCommand )
{
SRB *srb;
Nexus *nexus;
Nexus *nexusPhys;
UInt32 msgIndex;
SCSICDBInfo scsiCDB;
SCSITargetParms targetParms;
UInt32 i;
UInt32 tw;
srb = (SRB *)scsiCommand->getCommandData();
nexus = &srb->nexus;
nexusPhys = &srb->srbPhys->nexus;
scsiCommand->getCDB( &scsiCDB );
msgIndex = 0;
nexus->msg.ppData = OSSwapHostToLittleInt32((UInt32)&nexusPhys->msgData);
nexus->msgData[msgIndex++] = srb->lun | (( scsiCDB.cdbFlags & kCDBFlagsNoDisconnect ) ? 0x80 : 0xC0);
if ( scsiCDB.cdbTagMsg != 0 )
{
nexus->msgData[msgIndex++] = scsiCDB.cdbTagMsg;
nexus->msgData[msgIndex++] = srb->tag = srb->nexus.tag = scsiCDB.cdbTag + 128;
}
else
{
srb->tag = srb->nexus.tag = ((UInt32)srb->target << 3) | srb->lun;
}
scsiCommand->getDevice(kIOSCSIParallelDevice)->getTargetParms( &targetParms );
if ( scsiCDB.cdbFlags & (kCDBFlagsNegotiateWDTR | kCDBFlagsNegotiateSDTR) )
{
negotiateWDTRComplete = negotiateSDTRComplete = false;
}
if ( scsiCDB.cdbFlags & kCDBFlagsNegotiateWDTR )
{
nexus->msgData[msgIndex++] = kSCSIMsgExtended;
nexus->msgData[msgIndex++] = 2;
nexus->msgData[msgIndex++] = kSCSIMsgWideDataXferReq;
for ( tw = targetParms.transferWidth, i = (UInt32)-1;
tw;
tw >>= 1, i++ )
;
nexus->msgData[msgIndex++] = i;
}
if ( scsiCDB.cdbFlags & kCDBFlagsNegotiateSDTR )
{
nexus->msgData[msgIndex++] = kSCSIMsgExtended;
nexus->msgData[msgIndex++] = 3;
nexus->msgData[msgIndex++] = kSCSIMsgSyncXferReq;
if ( targetParms.transferOffset != 0 )
{
nexus->msgData[msgIndex++] = targetParms.transferPeriodpS / 4000;
nexus->msgData[msgIndex++] = targetParms.transferOffset;
}
else
{
nexus->msgData[msgIndex++] = 0;
nexus->msgData[msgIndex++] = 0;
}
}
srb->srbMsgLength = msgIndex;
if ((scsiCDB.cdbFlags & (kCDBFlagsNegotiateWDTR | kCDBFlagsNegotiateSDTR))
== (kCDBFlagsNegotiateWDTR | kCDBFlagsNegotiateSDTR))
{
msgIndex -= 5;
}
nexus->msg.length = OSSwapHostToLittleInt32( msgIndex );
srb->srbCDBFlags = scsiCDB.cdbFlags;
}
bool Sym8xxSCSIController::Sym8xxUpdateSGList( SRB *srb )
{
IOPhysicalSegment range;
UInt32 actRanges;
UInt32 offset;
UInt32 bytesLeft;
UInt32 i;
IOReturn rc = true;
offset = srb->xferOffset;
bytesLeft = srb->xferCount - srb->xferOffset;
if ( bytesLeft == 0 ) return rc;
i = 2;
while ( (bytesLeft > 0) && (i < MAX_SGLIST_ENTRIES-1))
{
actRanges = memoryCursor->getPhysicalSegments( srb->xferDesc,
offset,
&range,
1 );
if ( actRanges != 1 )
{
rc = false;
break;
}
srb->nexus.sgListData[i].physAddr = OSSwapHostToLittleInt32( (UInt32)range.location );
srb->nexus.sgListData[i].length = OSSwapHostToLittleInt32( range.length | srb->directionMask );
bytesLeft -= range.length;
offset += range.length;
i++;
}
if ( !bytesLeft )
{
srb->nexus.sgListData[i].length = OSSwapHostToLittleInt32( 0x90080000 );
srb->nexus.sgListData[i].physAddr = OSSwapHostToLittleInt32( 0x00000000 );
}
else
{
srb->nexus.sgListData[i].length = OSSwapHostToLittleInt32( 0x98080000 );
srb->nexus.sgListData[i].physAddr = OSSwapHostToLittleInt32( A_sglist_complete );
}
srb->xferOffsetPrev = srb->xferOffset;
srb->xferOffset = offset;
return rc;
}