#include <libkern/OSByteOrder.h>
#include <libkern/OSAtomic.h>
#include <IOKit/assert.h>
#include <IOKit/IOCommandGate.h>
#include <IOKit/IOTypes.h>
#include <IOKit/IOKitKeys.h>
#include <IOKit/pci/IOPCIDevice.h>
#include <IOKit/ata/IOATATypes.h>
#include <IOKit/ata/IOATAController.h>
#include <IOKit/ata/IOATACommand.h>
#include <IOKit/ata/IOATADevice.h>
#include <IOKit/ata/IOATABusInfo.h>
#include <IOKit/ata/IOATADevConfig.h>
#include "AppleKauaiATA.h"
#include <IOKit/ata/ATADeviceNub.h>
#ifdef DLOG
#undef DLOG
#endif
#ifdef ATA_DEBUG
#define DLOG(fmt, args...) IOLog(fmt, ## args)
#else
#define DLOG(fmt, args...)
#endif
#define ATARecordEventMACRO(type,param,bus,data) (void) (type); (void) (param); (void) (bus); (void) (data)
#define kCompatibleString "kauai-ata"
#define kCompatibleString2 "K2-UATA"
#define kCompatibleString3 "shasta-ata"
#define kModelPropertyKey "model"
#define kCableTypeKey "cable-type"
#define kModel6String "ata-6"
#define k80ConductorString "80-conductor"
#define kATASupportedPIOModes 0x001F // modes 4, 3, 2, 1, and 0
#define kATASupportedMultiDMAModes 0x0007 // modes 2, 1, and 0
#define kATASupportedUltraDMAModes 0x003f // modes 5, 4, 3, 2, 1, and 0
#define kATASupportedUltraDMA133Modes 0x007f // modes 6, 5, 4, 3, 2, 1, and 0
#define kAppleKauaiPIOCycleEntries 11
#define kAppleKauaiMultiDMACycleEntries 9
#define kAppleKauaiUltraDMACycleEntries 6
#define kAppleKauaiUltraDMA133CycleEntries 7
#define kATAMaxPIOMode 4
#define kATAMaxMultiDMAMode 2
#define kATAMaxUltraDMA133Mode 6
#define kATAXferDMADesc 33
#define kATAMaxDMADesc kATAXferDMADesc + 2
#define kMaxATAXfer 512 * 256
#define kRX_bufferSize 512 * 256
#pragma mark -IOService Overrides -
#define super MacIOATA
OSDefineMetaClassAndStructors( AppleKauaiATA, MacIOATA )
bool
AppleKauaiATA::init(OSDictionary* properties)
{
DLOG("AppleKauaiATA init start\n");
if (super::init(properties) == false)
{
DLOG("AppleKauaiATA: super::init() failed\n");
return false;
}
_needsResync = false;
dmaBuffer = 0;
clientBuffer = 0;
bufferRX = false;
rxFeatureOn = false;
ultra133 = false;
myProvider = 0;
#ifdef __KAUAI_POLLED__
polledAdapter = 0;
polledMode = false;
#endif
DLOG("AppleKauaiATA init done\n");
return true;
}
IOService*
AppleKauaiATA::probe(IOService* provider, SInt32* score)
{
OSData *compatibleEntry;
DLOG("AppleKauaiATA starting probe\n");
compatibleEntry = OSDynamicCast( OSData, provider->getProperty( "compatible" ) );
if ( compatibleEntry == 0 )
{
DLOG("AppleKauaiATA failed getting compatible property\n");
return 0;
}
if ( compatibleEntry->isEqualTo( kCompatibleString, sizeof(kCompatibleString)-1 ) == false )
{
if( compatibleEntry->isEqualTo( kCompatibleString2, sizeof(kCompatibleString2)-1 ) == false)
{
if( compatibleEntry->isEqualTo( kCompatibleString3, sizeof(kCompatibleString3)-1 ) == false)
{
DLOG("AppleKauaiATA compatible property doesn't match\n");
return 0;
}
ultra133 = true;
rxFeatureOn = true;
IOLog("AppleKauaiATA shasta-ata features enabled\n");
}
rxFeatureOn = true;
DLOG("AppleKauaiATA rx buffer feature enabled\n");
}
#ifdef __KAUAI_POLLED__
OSData *polledProperty = OSDynamicCast( OSData, provider->getProperty( kPolledPropertyKey ) );
if( polledProperty )
{
DLOG("AppleKauaiATA polledMode feature enabled\n");
polledMode = true;
} else {
;
DLOG("AppleKauaiATA polledMode property not found. \n");
}
#endif
OSData *registryEntry;
registryEntry = OSDynamicCast( OSData, provider->getProperty( kModelPropertyKey ) );
if( registryEntry == 0)
{
DLOG("AppleKauaiATA unknown model property.\n");
return 0;
}
busTimings[0].pioMWRegValue = busTimings[1].pioMWRegValue = 0x08000A92 | 0x00618000;
busTimings[0].ultraRegValue = busTimings[1].ultraRegValue = 0x00002921;
if( ultra133 )
{ busTimings[0].pioMWRegValue = busTimings[1].pioMWRegValue = 0x0a820c97; busTimings[0].ultraRegValue = busTimings[1].ultraRegValue = 0x00033031; }
busTimings[0].ataPIOSpeedMode = busTimings[1].ataPIOSpeedMode = 0x01 ; busTimings[0].ataPIOCycleTime = busTimings[1].ataPIOCycleTime = 600 ; busTimings[0].ataMultiDMASpeed = busTimings[1].ataMultiDMASpeed = 0x01; busTimings[0].ataMultiCycleTime = busTimings[1].ataMultiCycleTime = 480; busTimings[0].ataUltraDMASpeedMode = busTimings[1].ataUltraDMASpeedMode = 0x20;
return this;
}
bool
AppleKauaiATA::start(IOService *provider)
{
DLOG("AppleKauaiATA::start() begin\n");
if( ! OSDynamicCast(IOPCIDevice, provider ) )
{
DLOG("AppleKauaiATA provider not IOPCIDevice!\n");
return false;
}
if( ! provider->open(this) )
{
DLOG("AppleKauai provider did not open\n");
return false;
}
myProvider = provider;
if( rxFeatureOn )
{
dmaBuffer = IOBufferMemoryDescriptor::withOptions( kIOMemoryDirectionMask,
kRX_bufferSize,
4096);
if( ! dmaBuffer )
{
DLOG( "kauai ata failed to create dmaBuffer\n");
return false;
}
((IOPCIDevice *)provider)->configWrite8( (UInt8) 0xC, (UInt8) 0x08);
((IOPCIDevice *)provider)->configWrite8( (UInt8) 0x4, (UInt8) (((IOPCIDevice *)provider)->configRead8(0x4) | 0x10));
DLOG( "kauai ata created rx buffer\n");
}
((IOPCIDevice *)provider)->setMemoryEnable(true);
((IOPCIDevice *)provider)->setBusMasterEnable( true );
ATADeviceNub* newNub=0L;
if (!super::start( provider))
{
DLOG("AppleKauaiATA: super::start() failed\n");
provider->close(this);
return false;
}
#ifdef __KAUAI_POLLED__
if( polledMode )
{
polledAdapter = new KauaiPolledAdapter;
if( 0== polledAdapter)
{
DLOG(" AppleKauaiATA *** failed creating polled adapter\n");
} else {
polledAdapter->setOwner( this );
DLOG(" AppleKauaiATA polled adapter attached.\n");
setProperty ( kIOPolledInterfaceSupportKey, polledAdapter );
polledAdapter->release();
}
}
#endif
DLOG("AppleKauaiATA::start() done\n");
for( UInt32 i = 0; i < 2; i++)
{
if( _devInfo[i].type != kUnknownATADeviceType )
{
DLOG("AppleKauaiATA creating nub\n");
newNub = ATADeviceNub::ataDeviceNub( (IOATAController*)this, (ataUnitID) i, _devInfo[i].type );
if( newNub )
{
DLOG("AppleKauaiATA attach nub\n");
newNub->attach(this);
_nub[i] = (IOATADevice*) newNub;
DLOG("AppleKauaiATA register nub\n");
if( rxFeatureOn )
{
OSNumber* rx_alignLimit ;
rx_alignLimit = OSNumber::withNumber( (kRX_bufferSize), 32);
newNub->setProperty( kIOMaximumByteCountReadKey, rx_alignLimit);
rx_alignLimit->release();
}
newNub->registerService();
newNub = 0L;
}
}
}
return true;
}
void
AppleKauaiATA::free()
{
super::free();
}
IOWorkLoop*
AppleKauaiATA::getWorkLoop() const
{
IOWorkLoop* wl = _workLoop;
if (!wl)
{
wl = IOWorkLoop::workLoop();
if (!wl)
return 0;
}
return wl;
}
bool
AppleKauaiATA::configureTFPointers(void)
{
DLOG("AppleKauaiATA config TF Pointers \n");
DLOG("AppleKauaiATA configureTFPointers begin\n");
_baseAddressMap = _provider->mapDeviceMemoryWithIndex(0);
if( !_baseAddressMap )
{
DLOG("AppleKauaiATA no base map\n");
return false;
}
volatile UInt8* baseAddress = (volatile UInt8*)_baseAddressMap->getVirtualAddress();
if( !baseAddress )
{
DLOG("AppleKauaiATA no base address\n");
return false;
}
_kauaiATAFCR = (volatile UInt32*) baseAddress;
DLOG("MacIOATA baseAdress = %lx\n", baseAddress);
_dmaControlReg = (volatile IODBDMAChannelRegisters*) (baseAddress + 0x1000);
baseAddress += 0x2000;
_tfDataReg = (volatile UInt16*) (baseAddress + 0x00);
_tfFeatureReg = baseAddress + 0x10;
_tfSCountReg = baseAddress + 0x20;
_tfSectorNReg = baseAddress + 0x30;
_tfCylLoReg = baseAddress + 0x40;
_tfCylHiReg = baseAddress + 0x50;
_tfSDHReg = baseAddress + 0x60;
_tfStatusCmdReg = baseAddress + 0x70;
_tfAltSDevCReg = baseAddress + 0x160;
_timingConfigReg = (volatile UInt32*) (baseAddress + 0x200);
_ultraTimingControl = (volatile UInt32*) (baseAddress + 0x210);
_autoPollingControl = (volatile UInt32*) (baseAddress + 0x220);
_interruptPendingReg = (volatile UInt32*) (baseAddress + 0x300);
DLOG("MacIOATA configureTFPointers end\n");
DLOG("AppleKauaiATA enable FCR \n");
OSWriteSwapInt32(_kauaiATAFCR, 0, 0x00000007 );
DLOG("AppleKauaiATA setting default timing \n");
selectIOTiming( (ataUnitID) 0 );
DLOG("AppleKauaiATA configTFPointers done\n");
return true;
}
IOReturn
AppleKauaiATA::provideBusInfo( IOATABusInfo* infoOut)
{
if( infoOut == 0)
{
DLOG("AppleKauaiATA nil pointer in provideBusInfo\n");
return -1;
}
infoOut->zeroData();
infoOut->setSocketType( kInternalATASocket );
infoOut->setPIOModes( kATASupportedPIOModes);
infoOut->setDMAModes( kATASupportedMultiDMAModes );
infoOut->setUltraModes( kATASupportedUltraDMAModes );
if( ultra133 )
{
infoOut->setUltraModes( kATASupportedUltraDMA133Modes );
}
infoOut->setExtendedLBA( true ); infoOut->setMaxBlocksExtended( 0x0800 ); if( rxFeatureOn)
infoOut->setMaxBlocksExtended( 0x0100 );
UInt8 units = 0;
if( _devInfo[0].type != kUnknownATADeviceType )
units++;
if( _devInfo[1].type != kUnknownATADeviceType )
units++;
infoOut->setUnits( units);
return kATANoErr;
}
IOReturn
AppleKauaiATA::getConfig( IOATADevConfig* configRequest, UInt32 unitNumber)
{
if( configRequest == 0
|| unitNumber > 1 )
{
DLOG("AppleKauaiATA bad param in getConfig\n");
return -1;
}
configRequest->setPIOMode( busTimings[unitNumber].ataPIOSpeedMode);
configRequest->setDMAMode(busTimings[unitNumber].ataMultiDMASpeed);
configRequest->setPIOCycleTime(busTimings[unitNumber].ataPIOCycleTime );
configRequest->setDMACycleTime(busTimings[unitNumber].ataMultiCycleTime);
configRequest->setPacketConfig( _devInfo[unitNumber].packetSend );
configRequest->setUltraMode(busTimings[unitNumber].ataUltraDMASpeedMode);
return kATANoErr;
}
IOReturn
AppleKauaiATA::selectConfig( IOATADevConfig* configRequest, UInt32 unitNumber)
{
if( configRequest == 0
|| unitNumber > 1 )
{
DLOG("AppleKauaiATA bad param in setConfig\n");
return -1;
}
if( ( configRequest->getPIOMode() & kATASupportedPIOModes ) == 0x00 )
{
DLOG("AppleKauaiATA setConfig PIO mode not supported\n");
return kATAModeNotSupported;
}
UInt8 ultraSupported = kATASupportedUltraDMAModes;
if( ultra133 )
{
ultraSupported = kATASupportedUltraDMA133Modes;
}
if( configRequest->getUltraMode() & ~ultraSupported )
{
DLOG("AppleKauaiATA setConfig no ultra\n");
return kATAModeNotSupported;
}
if( configRequest->getDMAMode() & ~kATASupportedMultiDMAModes )
{
DLOG("AppleKauaiATA setConfig DMA mode not supported\n");
return kATAModeNotSupported;
}
if( configRequest->getDMAMode() > 0x0000
&& configRequest->getUltraMode() > 0x0000 )
{
DLOG("AppleKauaiATA err, only one DMA class allowed in config select\n");
return kATAModeNotSupported;
}
_devInfo[unitNumber].packetSend = configRequest->getPacketConfig();
DLOG("AppleKauaiATA setConfig packetConfig = %ld\n", _devInfo[unitNumber].packetSend );
return selectIOTimerValue(configRequest, unitNumber);
}
IOReturn
AppleKauaiATA::selectIOTimerValue( IOATADevConfig* configRequest, UInt32 unitNumber)
{
static const UInt16 MinPIOCycle[kATAMaxPIOMode + 1] =
{
600, 383, 240, 180, 120 };
static const UInt16 MinMultiDMACycle[kATAMaxMultiDMAMode + 1] =
{
480, 150, 120 };
UInt32 PIOCycleValue100[kAppleKauaiPIOCycleEntries] =
{
0x08000FFF, 0x08000A92, 0x0800060F, 0x08000492, 0x0800048F, 0x080003CF, 0x080003CC, 0x0800038B, 0x0800030C, 0x05000249, 0x04000148 };
UInt32 PIOCycleValue133[kAppleKauaiPIOCycleEntries] =
{
0x08000FFF, 0x0A000C97, 0x07000712, 0x040003CD, 0x040003CD, 0x040003CD, 0x040003CD, 0x040003CD, 0x040003CD, 0x0400028B, 0x0400010A };
static const UInt16 PIOCycleTime[ kAppleKauaiPIOCycleEntries ]=
{
930, 600, 383, 360, 330, 300, 270, 240, 239, 180, 120, };
static const UInt32 MultiDMACycleValue100[kAppleKauaiMultiDMACycleEntries] =
{
0x00FFF000, 0x00618000, 0x00492000, 0x0038E000, 0x0030C000, 0x002CB000, 0x00249000, 0x00209000, 0x00148000 };
static const UInt32 MultiDMACycleValue133[kAppleKauaiMultiDMACycleEntries] =
{
0x00FFF000, 0x00820800, 0x00820800, 0x00820800, 0x00820800, 0x00820800, 0x00820800, 0x0028B000, 0x001CA000 };
static const UInt16 MultiDMACycleTime[kAppleKauaiMultiDMACycleEntries] =
{
1260, 480, 360, 270, 240, 210, 180, 150, 120 };
static const UInt32 UltraDMACycleValue100[kAppleKauaiUltraDMACycleEntries ] =
{
0x000070C1, 0x00005D81, 0x00004A61, 0x00003A51, 0x00002A31, 0x00002921 };
static const UInt32 UltraDMACycleValue133[kAppleKauaiUltraDMA133CycleEntries] =
{
0x00035901, 0x000348b1, 0x00033881, 0x00033861, 0x00033841, 0x00033031, 0x00033021 };
#ifdef ATA_DEBUG
static const UInt16 UltraDMACycleTime100[kAppleKauaiUltraDMACycleEntries] =
{
120, 90, 60, 45, 30, 20
};
static const UInt16 UltraDMACycleTime133[kAppleKauaiUltraDMA133CycleEntries] =
{
120, 90, 60, 45, 30, 20, 15 };
#endif
UInt32 pioConfigBits = PIOCycleValue100[0];
if( ultra133 )
{
pioConfigBits = PIOCycleValue133[0];
}
UInt32 pioModeNumber = bitSigToNumeric( configRequest->getPIOMode());
if( pioModeNumber > kATAMaxPIOMode )
{
DLOG("AppleKauaiATA pio mode out of range\n");
return kATAModeNotSupported;
}
UInt32 pioCycleTime = configRequest->getPIOCycleTime();
if( pioCycleTime < MinPIOCycle[ pioModeNumber ] )
{
pioCycleTime = MinPIOCycle[ pioModeNumber ];
}
for( int i = kAppleKauaiPIOCycleEntries - 1; i >= 0; i--)
{
if( pioCycleTime <= PIOCycleTime[ i ] )
{
pioConfigBits = PIOCycleValue100[i];
if( ultra133 )
{
pioConfigBits = PIOCycleValue133[i];
}
break;
}
}
UInt32 mwdmaConfigBits = MultiDMACycleValue100[0];
if( ultra133 )
{
mwdmaConfigBits = MultiDMACycleValue133[0];
}
UInt32 dmaModeNumber = 0;
UInt32 dmaCycleTime = 0;
if( configRequest->getDMAMode() )
{
dmaModeNumber = bitSigToNumeric( configRequest->getDMAMode() );
if( dmaModeNumber > kATAMaxMultiDMAMode )
{
dmaModeNumber = 0;
}
dmaCycleTime = configRequest->getDMACycleTime();
if( dmaCycleTime < MinMultiDMACycle[ dmaModeNumber ] )
{
dmaCycleTime = MinMultiDMACycle[ dmaModeNumber ];
}
for( int i = kAppleKauaiMultiDMACycleEntries - 1; i >= 0; i--)
{
if( dmaCycleTime <= MultiDMACycleTime[ i ] )
{
mwdmaConfigBits = MultiDMACycleValue100[i];
if( ultra133 )
{
mwdmaConfigBits = MultiDMACycleValue133[i];
}
break;
}
}
}
UInt32 ultraModeNumber = 0;
UInt32 ultraConfigBits = 0;
if( configRequest->getUltraMode() )
{
ultraModeNumber = bitSigToNumeric( configRequest->getUltraMode() );
if( ultra133 )
{
if( ultraModeNumber > 6)
ultraModeNumber = 6;
ultraConfigBits = UltraDMACycleValue133[ ultraModeNumber ];
} else {
if( ultraModeNumber > 5 )
ultraModeNumber = 5;
ultraConfigBits = UltraDMACycleValue100[ ultraModeNumber ];
}
}
busTimings[unitNumber].pioMWRegValue = mwdmaConfigBits | pioConfigBits;
busTimings[unitNumber].ultraRegValue = ultraConfigBits;
busTimings[unitNumber].ataPIOSpeedMode = configRequest->getPIOMode();
busTimings[unitNumber].ataPIOCycleTime = pioCycleTime;
busTimings[unitNumber].ataMultiDMASpeed = configRequest->getDMAMode();
busTimings[unitNumber].ataMultiCycleTime = dmaCycleTime;
busTimings[unitNumber].ataUltraDMASpeedMode = configRequest->getUltraMode();
DLOG("AppleKauaiATA PIO mode %x at %ld ns selected for device: %x\n", (int)pioModeNumber, pioCycleTime, (int)unitNumber);
DLOG("AppleKauaiATA DMA mode %x at %ld ns selected for device: %x\n", (int)dmaModeNumber, dmaCycleTime, (int)unitNumber);
DLOG("AppleKauaiATA Ultra mode %x at %ld ns selected for device: %x\n", (int)ultraModeNumber, UltraDMACycleTime133[ultraModeNumber], (int)unitNumber);
DLOG("AppleKauai pio/mw cycle value = %x for unit: %x\n", busTimings[unitNumber].pioMWRegValue, unitNumber);
DLOG("AppleKauai ultra cycle value = %x for unit: %x\n", busTimings[unitNumber].ultraRegValue, unitNumber);
return getConfig( configRequest, unitNumber);
}
void
AppleKauaiATA::selectIOTiming( ataUnitID unit )
{
OSWriteSwapInt32( _kauaiATAFCR, 0, 0x7);
OSWriteSwapInt32(_timingConfigReg, 0, busTimings[unit].pioMWRegValue );
OSWriteSwapInt32( _ultraTimingControl, 0, busTimings[unit].ultraRegValue);
}
IOReturn
AppleKauaiATA::handleDeviceInterrupt(void)
{
if( !_currentCommand )
{
volatile UInt8 status = *_tfStatusCmdReg;
OSSynchronizeIO();
status++; return 0;
}
UInt32 intStatus = OSReadLittleInt32( (void*) _interruptPendingReg, 0x00);
OSSynchronizeIO();
if( !(intStatus & 0x40000000)
&& !_needsResync )
{
volatile UInt8 status = *_tfStatusCmdReg;
OSSynchronizeIO();
status++;
return 0;
}
return super::handleDeviceInterrupt();
}
IOReturn
AppleKauaiATA::selectDevice( ataUnitID unit )
{
_devIntSrc->disable();
IOReturn result = super::selectDevice( unit);
_devIntSrc->enable();
return result;
}
IOReturn
AppleKauaiATA::synchronousIO(void)
{
_devIntSrc->disable();
IOReturn result = super::synchronousIO();
UInt32 intStatus = OSReadLittleInt32( (void*) _interruptPendingReg, 0x00);
OSSynchronizeIO();
while( (intStatus & 0x40000000) )
{
volatile UInt8 status = *_tfStatusCmdReg;
OSSynchronizeIO();
status++;
intStatus = OSReadLittleInt32( (void*) _interruptPendingReg, 0x00);
OSSynchronizeIO();
}
_devIntSrc->enable();
return result;
}
IOReturn
AppleKauaiATA::handleBusReset(void)
{
bool isATAPIReset = ((_currentCommand->getFlags() & mATAFlagProtocolATAPI) != 0);
bool doATAPI[2];
IOReturn err = kATANoErr;
UInt8 index;
UInt8 statCheck;
DLOG("AppleKauaiATA bus reset start.\n");
doATAPI[0] = doATAPI[1] = false;
if(isATAPIReset)
{
doATAPI[_currentCommand->getUnit()] = true; }
for(index=0;index<2;index++)
{
if( doATAPI[index] && _devInfo[index].type == kATAPIDeviceType)
{
OSSynchronizeIO();
*_tfSDHReg = mATASectorSize + (index << 4);
OSSynchronizeIO();
statCheck = *_tfAltSDevCReg;
err = softResetBus(true);
}
}
if(isATAPIReset) {
if( polledAdapter && polledAdapter->isPolling() )
{
; } else {
executeEventCallouts( kATAPIResetEvent, _currentCommand->getUnit() );
}
}
if(!isATAPIReset)
{
err = softResetBus();
if( polledAdapter && polledAdapter->isPolling() )
{
; } else {
executeEventCallouts( kATAResetEvent, kATAInvalidDeviceID );
}
}
_currentCommand->state = IOATAController::kATAComplete;
DLOG("AppleKauaiATA bus reset done.\n");
completeIO( err );
return err;
}
IOATAController::transState
AppleKauaiATA::determineATAPIState(void)
{
IOATAController::transState drivePhase = super::determineATAPIState();
if( _currentCommand->state > drivePhase
|| _currentCommand->state == kATAStarted )
{
return (IOATAController::transState) _currentCommand->state;
}
return drivePhase;
}
void
AppleKauaiATA::processDMAInterrupt(void)
{
_needsResync = _resyncInterrupts;
OSWriteLittleInt32( (void*) _interruptPendingReg, 0x00, 0x80000000); super::processDMAInterrupt();
_needsResync = false;
}
bool
AppleKauaiATA::allocDMAChannel(void)
{
if( !_dmaControlReg )
{
DLOG("AppleKauaiATA no DMA address\n");
return false;
}
_descriptors = (IODBDMADescriptor*)IOMallocContiguous( sizeof(IODBDMADescriptor) * kATAMaxDMADesc,
0x10,
&_descriptorsPhysical );
if( ! _descriptors )
{
DLOG("AppleKauaiATA alloc descriptors failed\n");
return false;
}
_DMACursor = IODBDMAMemoryCursor::withSpecification(0xFFFE,
kMaxATAXfer
);
if( ! _DMACursor )
{
DLOG("AppleKauaiATA alloc DMACursor failed\n");
return false;
}
initATADMAChains(_descriptors);
return true;
}
IOReturn
AppleKauaiATA::handleExecIO( void )
{
if( ! rxFeatureOn)
goto preflightDone;
DLOG("AppleKauaiATA checking flags %X\n", _currentCommand->getFlags() );
if( _currentCommand->getFlags() & (mATAFlagUseDMA)
&& _currentCommand->getFlags() & (mATAFlagIORead) )
{
DLOG("AppleKauaiATA checking alignment\n");
if(_currentCommand->getOpcode() == kATAPIFnExecIO)
{
DLOG("AppleKauaiATA ATAPI length check\n");
UInt32 remainder = _currentCommand->getByteCount() % 16;
if( remainder )
{
DLOG("AppleKauaiATA convert ATAPI to PIO remainder = %d\n", remainder);
_currentCommand->setFlags( _currentCommand->getFlags() & (~mATAFlagUseDMA) );
_currentCommand->getTaskFilePtr()->ataTFFeatures &= 0xFE;
goto preflightDone;
}
if( _currentCommand->getByteCount() > kRX_bufferSize )
{
DLOG("AppleKauaiATA count exceeds buffer size!!! %d\n", _currentCommand->getByteCount());
goto preflightDone;
}
DLOG("AppleKauaiATA double buffering dma\n");
clientBuffer = _currentCommand->getBuffer();
bufferRX = true;
_currentCommand->setBuffer(dmaBuffer);
dmaBuffer->prepare(kIODirectionIn);
}
}
preflightDone:
return super::handleExecIO();
}
void
AppleKauaiATA::completeIO( IOReturn commandResult )
{
if( bufferRX )
{
DLOG("AppleKauaiATA complete double buffer\n");
bufferRX = false;
dmaBuffer->complete(kIODirectionIn);
clientBuffer->writeBytes(0, dmaBuffer->getBytesNoCopy(), _currentCommand->getActualTransfer() );
_currentCommand->setBuffer( clientBuffer );
clientBuffer = 0;
}
super::completeIO( commandResult );
}
void
AppleKauaiATA::handleTimeout( void )
{
#ifdef ATA_DEBUG
DLOG("AppleKauaiATA handleTimeout cmd flags %X\n", _currentCommand->getFlags() );
DLOG("AppleKauaiATA handleTimeout byte count%d\n", _currentCommand->getByteCount() );
DLOG("AppleKauaiATA handleTimeout _dmaIntExpected (true if non-zero value) = %X\n", _dmaIntExpected );
DLOG("AppleKauaiATA handleTimeout DMA state flag %X\n", _dmaState );
IOMemoryDescriptor* theClientBuffer = _currentCommand->getBuffer();
DLOG("AppleKauaiATA handleTimeout buffer direction %d\n" ,theClientBuffer->getDirection());
DLOG("AppleKauaiATA handleTimeout buffer length %d\n", theClientBuffer->getLength());
DLOG("AppleKauaiATA handleTimeout buffer physical address %X\n",theClientBuffer->getPhysicalAddress());
IODBDMADescriptor* descPtr = _descriptors;
DLOG("AppleKauaiATA handleTimeout dumping CC chain\n");
DLOG("ChanStat= %lx\n", IOGetDBDMAChannelStatus(_dmaControlReg));
for( int index = 0; index < kATAMaxDMADesc; index++)
{
DLOG(" index=%d ccOpr = %lx, ccAddr = %lx, ccCmd = %lx, ccResult= %lx \n",
index,
IOGetCCOperation( descPtr ),
IOGetCCAddress(descPtr),
IOGetCCCmdDep(descPtr),
IOGetCCResult(descPtr) );
descPtr++;
}
#endif
super::handleTimeout();
}
void
AppleKauaiATA::activateDMAEngine(void)
{
if( IOGetDBDMAChannelStatus( _dmaControlReg) & kdbdmaActive )
{
shutDownATADMA();
}
IOSetDBDMACommandPtr( _dmaControlReg, (unsigned int) _descriptorsPhysical);
IOSetDBDMAWaitSelect (_dmaControlReg, kdbdmaS7 << 16);
_dmaIntExpected = true;
IOSetDBDMAChannelControl(_dmaControlReg, IOSetDBDMAChannelControlBits( kdbdmaRun | kdbdmaWake));
}
IOReturn
AppleKauaiATA::createChannelCommands(void)
{
IOMemoryDescriptor* descriptor = _currentCommand->getBuffer();
if( ! descriptor )
{
DLOG("AppleKauaiATA nil DMA buffer!\n");
return -1;
}
IOByteCount bytesRemaining = _currentCommand->getByteCount()
- _currentCommand->getActualTransfer();
IOByteCount xfrPosition = _currentCommand->getPosition() +
_currentCommand->getActualTransfer();
IOByteCount transferSize = 0;
UInt32 segmentCount = _DMACursor->getPhysicalSegments(
descriptor,
xfrPosition,
_descriptors,
kATAXferDMADesc,
bytesRemaining, &transferSize);
if( transferSize > bytesRemaining)
{
DLOG("AppleKauaiATA DMA too long!!!\n");
return -1;
}
if( segmentCount == 0)
{
DLOG("AppleKauaiATA seg count 0!!!\n");
return -1;
}
if( transferSize < bytesRemaining )
{
_dmaState = kATADMAActive;
DLOG("AppleKauaiATA will make two passes\n");
} else {
_dmaState = kATADMAStatus;
DLOG("AppleKauaiATA will make one pass\n");
}
UInt32 command = kdbdmaOutputMore;
if( _currentCommand->getFlags() & mATAFlagIORead)
{
command = kdbdmaInputMore;
}
DLOG("AppleKauaiATA making CC chain for %ld segs for xfersize %ld\n", segmentCount, transferSize);
for( UInt32 i = 0; i < segmentCount; i++)
{
IODBDMADescriptor* currDesc = & (_descriptors[i]);
UInt32 addr = IOGetCCAddress(currDesc);
UInt32 count = IOGetCCOperation(currDesc) & kdbdmaReqCountMask;
OSSynchronizeIO();
if( (i == (segmentCount -1) ) )
{
if( command == kdbdmaOutputMore)
{
command = kdbdmaOutputLast;
} else {
command = kdbdmaInputLast;
}
IOMakeDBDMADescriptor(currDesc,
command,
kdbdmaKeyStream0,
kdbdmaIntNever,
kdbdmaBranchNever,
kdbdmaWaitIfTrue,
count,
addr);
} else {
IOMakeDBDMADescriptor(currDesc,
command,
kdbdmaKeyStream0,
kdbdmaIntNever,
kdbdmaBranchNever,
kdbdmaWaitNever,
count,
addr);
}
DLOG("AppleKauaiATA desc# %ld at %x \n", i, currDesc );
DLOG("addr = %lx count = %lx \n", addr, count );
DLOG("%lx %lx %lx %lx\n", currDesc->operation, currDesc->address ,currDesc->cmdDep ,currDesc->result );
}
IOMakeDBDMADescriptor(&(_descriptors[segmentCount]),
kdbdmaNop,
kdbdmaKeyStream0,
kdbdmaIntAlways,
kdbdmaBranchNever,
kdbdmaWaitNever,
0,
0);
IOMakeDBDMADescriptor(&(_descriptors[segmentCount + 1]),
kdbdmaStop,
kdbdmaKeyStream0,
kdbdmaIntNever,
kdbdmaBranchNever,
kdbdmaWaitNever,
0,
0);
return kATANoErr;
}
#pragma mark -- Polled Interface --
#ifdef __KAUAI_POLLED__
IOReturn
AppleKauaiATA::startTimer( UInt32 inMS)
{
if( polledAdapter )
{
if(polledAdapter->isPolling())
return 0;
}
return super::startTimer( inMS);
}
void
AppleKauaiATA::stopTimer(void)
{
if( polledAdapter )
{
if(polledAdapter->isPolling())
return ;
}
return super::stopTimer( );
}
void
AppleKauaiATA::pollEntry( void )
{
if( 0 == _currentCommand )
return;
if( _dmaIntExpected )
{
volatile IODBDMADescriptor* descPtr = _descriptors;
enum {
OUTPUT_MORE = 0x00000000,
OUTPUT_LAST = 0x10000000,
INPUT_MORE = 0x20000000,
INPUT_LAST = 0x30000000,
STORE_QUAD = 0x40000000,
LOAD_QUAD = 0x50000000,
NOP_CMD = 0x60000000,
STOP_CMD = 0x70000000,
kdbdmaCmdMask = (long)0xF0000000
};
while ((IOGetCCOperation(descPtr) & kdbdmaCmdMask) != NOP_CMD)
{
descPtr++;
continue;
}
if ( !(IOGetCCResult(descPtr) & 0x80000000) )
{
return;
}
}
UInt32 intStatus = OSReadLittleInt32( (void*) _interruptPendingReg, 0x00);
if( _dmaIntExpected)
{
if( (intStatus & 0xC0000000) == 0xC0000000 )
{
processDMAInterrupt();
handleDeviceInterrupt();
}
return;
}
if( intStatus & 0x40000000 )
{
handleDeviceInterrupt();
return;
}
return;
}
void
AppleKauaiATA::transitionFixup( void )
{
_needsResync = false;
bufferRX = false;
clientBuffer = 0;
_dmaIntExpected = 0;
_dmaState = MacIOATA::kATADMAInactive;
_resyncInterrupts = false;
isBusOnline = true;
_queueState = IOATAController::kQueueOpen;
_busState = IOATAController::kBusFree;
_currentCommand = 0L;
_selectedUnit = kATAInvalidDeviceID;
_queueState = IOATAController::kQueueOpen;
_immediateGate = IOATAController::kImmediateOK;
((IOPCIDevice *)myProvider)->restoreDeviceState();
}
#endif
#ifdef __KAUAI_POLLED__
#undef super
#define super IOPolledInterface
OSDefineMetaClassAndStructors( KauaiPolledAdapter, IOPolledInterface )
IOReturn
KauaiPolledAdapter::probe(IOService * target)
{
pollingActive = false;
return kIOReturnSuccess;
}
IOReturn
KauaiPolledAdapter::open( IOOptionBits state, IOMemoryDescriptor * buffer)
{
switch( state )
{
case kIOPolledPreflightState:
break;
case kIOPolledBeforeSleepState:
pollingActive = true;
break;
case kIOPolledAfterSleepState:
owner->transitionFixup();
pollingActive = true;
break;
case kIOPolledPostflightState:
default:
break;
}
return kIOReturnSuccess;
}
IOReturn
KauaiPolledAdapter::close(IOOptionBits state)
{
switch( state )
{
case kIOPolledPreflightState:
case kIOPolledBeforeSleepState:
case kIOPolledAfterSleepState:
case kIOPolledPostflightState:
default:
pollingActive = false;
break;
}
return kIOReturnSuccess;
}
IOReturn
KauaiPolledAdapter::startIO(uint32_t operation,
uint32_t bufferOffset,
uint64_t deviceOffset,
uint64_t length,
IOPolledCompletion completion)
{
return kIOReturnUnsupported;
}
IOReturn
KauaiPolledAdapter::checkForWork(void)
{
if( owner )
{
owner->pollEntry();
}
return kIOReturnSuccess;
}
bool
KauaiPolledAdapter::isPolling( void )
{
return pollingActive;
}
void
KauaiPolledAdapter::setOwner( AppleKauaiATA* myOwner )
{
owner = myOwner;
pollingActive = false;
}
#endif