Jump to content

S-ATA & IOKitWait timeout...


Ztardust
 Share

58 posts in this topic

Recommended Posts

Hey!

 

I´ve been trying a lot of different kexts in an attempt to get my boot time down...

 

If I delete the IOATAFamily kext(or other S-ATA relevant kexts), and just startup from my external USB disk, I get rid of the IOKitWaitQuiet timeout and my boot time is only 33 seconds.

 

But when I try to use AppleViaAta or other kexts to get my internal sata disk booting, I get the IOKitWaitQuiet timeout and the boot takes about 1 minute 15 seconds.

I feel like I´ve tried everything, but the boot time sits there on 1:15 like a wall...

 

I´m using the machine in my signature, Acer Aspire 5104, with S-ATA 150, ATI SATA controller(ID: 4379:1002).

 

Any suggestions?

Link to comment
Share on other sites

I don't know how yet but I'm certain that this timeout value can be changed if we had access to the source code for the kext that IOKitWait is from. It's probably from IOATAFamily.kext. If so, all we really have to do is time how long the timeout lasts for and search for that value in the source code, change it to an extremely low value and build it in Xcode again.

 

I've never tried this, but it should have some sort of variable, all timeouts usually does have a hardcoded variable that we can change this way.

Link to comment
Share on other sites

I'm find in IOATAFamily source timeout on 31sec

 

i'm done it

 

THANK YOU THANK YOU THANK YOU!!!!

 

You solved my problem!

 

I really had only two problems left on my machine, not having 100% support for my graphics card(only 1024x768 on internal screen), and this IOKitWaitQuiet timeout.

For me the most important of these problems was the timeout problem, since I often need to be able to start up the machine quickly. This cut my startup time from about 1:15 to ca. 40 seconds.

 

Do you mind perhaps giving a quick explanation of exactly how you did this?

I know a lot of people have had this issue, and it would be good to know how you fixed this, in case there is an update of OSX that requires a new version of this kext...

 

Again thank you!!

 

- Ztardust -

Link to comment
Share on other sites

I'm fix IOATAController.cpp

 

before:

for( int i = 0; i < 3100; i++)
{

	// read the status register - helps deal with devices which errantly 
	// set interrupt pending states during resets. Reset operations are not 
	// supposed to generate interrupts, but some devices do anyway.
	// interrupt handlers should be prepared to deal with errant interrupts on ATA busses.
	OSSynchronizeIO();
	UInt8 status = *_tfStatusCmdReg;	  

	// when drive is ready, break the loop
	if( ( status & readyMask )== readyOn)
	{
		// device reset completed in time
		resetFailed = false;
		break;
	}

	IOSleep( 10 );  // sleep thread for another 10 ms

}


if( resetFailed )
{
	// it is likely that this hardware is broken. 
	// There's no recovery action if the drive fails 
	// to reset.	
	DLOG("IOATA device failed to reset.\n");	
	result = kATATimeoutErr;
}

DLOG("IOATA reset complete.\n");

return result;

}


/*---------------------------------------------------------------------------
*
* Subclasses should take necessary action to create DMA channel programs, 
* for the current memory descriptor in _currentCommand and activate the 
* the DMA hardware
---------------------------------------------------------------------------*/
IOReturn
IOATAController::startDMA( void )
{


DLOG("IOATA Bus controllers that offer DMA must provide implementation/n");

return kATAModeNotSupported;
}




/*---------------------------------------------------------------------------
* Subclasses should take all actions necesary to safely shutdown DMA engines
* in any state of activity, whether finished, pending or stopped. Calling 
* this function must be harmless reguardless of the state of the engine.
*
---------------------------------------------------------------------------*/
IOReturn
IOATAController::stopDMA( void )
{

DLOG("IOATA Bus controllers that offer DMA must provide implementation/n");

return kATAModeNotSupported;
}


/*---------------------------------------------------------------------------
//	WaitForU8Status
//	Will wait up to one millisecond for the value in the altStatus register & mask to equal the value
//	passed in. Note that I always use the altStatus register so as not to have the side affect of clearing
//	the interrupt if there is one.
---------------------------------------------------------------------------*/
bool		
IOATAController::waitForU8Status (UInt8 mask, UInt8 value)
{
int	i;

// we will read the status from the alt status register so as not
// to clear the interrupt accidentally

for (i=0; i < kStatusDelayLoopMS; i++)
{
	OSSynchronizeIO();

	if ((*_tfAltSDevCReg & mask) == value)
	{
		return true;
	}

	IODelay( kStatusDelayTime );
}
return false;																	// time's up
}

/*----------------------------------------------------------------------------------------------------
**	Routine 	ATAPISlaveExists
**
**	Purpose:   Determines whether an ATAPI device seen as a "slave" of a master ATAPI device
**			   is actually present, or the product of the master shadowing a not-present slave's registers
**			   Call this function when the master device shows EBh 14h, and the slave also shows the ATAPI
**			   protocol signature.
**	Returns:   False if a device is ruled out. True if a device is verified. Leaves device in a ready state,
** 			   But no longer showing signatures. 

NOTE:	 Device 1 (slave) is assumed already selected.
*/


bool 
IOATAController::ATAPISlaveExists( void )
{
UInt8						scratchByte;
UInt16						scratchWord;
UInt32						dataCounter;
UInt32						loopCounter;

// The only option is to issue a command and see what happens.
OSSynchronizeIO();		
*_tfAltSDevCReg = 0x02; // disable interrupts

//issue INDENTIFY PACKET DEVICE 
OSSynchronizeIO();	
*_tfStatusCmdReg = 0xA1;  

// reading and disreguarding a register provides the required 400ns delay time.
OSSynchronizeIO();	
scratchByte = *_tfAltSDevCReg;

OSSynchronizeIO();	
scratchByte = *_tfAltSDevCReg;

// if the device returns status 00h, we declare it not present. A real device would probably be 
// status BSY (80h) now. An incredibly fast device might be ready to move data and show DRQ.
// However, by ATA standards, a not present device is required to return 00h.
// Lucky break, no device and we figured it out in a hurry.

if( (scratchByte == 0x00) )
{
	// enable device interrupt
	*_tfAltSDevCReg = 0x00;
	OSSynchronizeIO();
	return false;
}

// OK we probably have a device now. We have to wait for drive to send data, and read it and clear it.
// It is possible that the a misbehaving master has decided to respond to the command. So, we'll
// break on error bit and say it's not a real slave should that happen.

// take a leisurely approach, this will take a while.

// give the device up to 10 seconds to respond with data.
for( loopCounter = 0; loopCounter < 10000; loopCounter++)   
{		
	OSSynchronizeIO();
	scratchByte =  *_tfAltSDevCReg;

	// If drive sets error, clear status and return false. It's probably a misbehaving master
	if( scratchByte & 0x01 )
		break;		

	// this means the drive is really there. Clear the data and return true.
	if( (scratchByte & 0x58) == 0x58)  // RDY=1  DRQ=1
	{
		OSSynchronizeIO();
		scratchByte = *_tfStatusCmdReg; // clear pending interrupt state

		for( dataCounter = 0; dataCounter < 256; dataCounter++ )
		{
			OSSynchronizeIO();
			scratchWord = *_tfDataReg;
		}				
		// enable device interrupt
		*_tfAltSDevCReg = 0x00;
		OSSynchronizeIO();
		return true;		
	}

	// OK, sleep for 10 ms and try again.
	IOSleep(10);			
}

// In the ugly case, a drive set BSY, and didn't respond within 10 seconds with data.
// Otherwise, this is the for loop terminating on seeing the error bit.
// We'll read status and return false.

OSSynchronizeIO();
scratchByte = *_tfStatusCmdReg; // clear pending interrupt state	

// enable device interrupt
*_tfAltSDevCReg = 0x00;
OSSynchronizeIO();

return false;

}



/*---------------------------------------------------------------------------
*	scan the bus to see if devices are attached. The assumption is that the 
*  devices are in a cleanly-reset state, showing their protocol signatures, 
*  and the bus is properly wired with a pull down resistor on DD:7.
*	If your bus controller does not meet these conditions, you should override 
*	and supply your own function which meets your specific hardware needs.
*	Your controller may or may not require a reset, or it may require more 
*  thorough scanning, or additional configuration prior to looking for drives,
*	or it may aquire information from firmware indicating the devices attached.
*	This function should be self contained and not rely upon work loop or 
* 	or anything other than the register pointers being setup and enabled for access
---------------------------------------------------------------------------*/

UInt32 
IOATAController::scanForDrives( void )
{
UInt32 unitsFound = 0;
UInt8 status = 0x00;
// count total time spent searching max time allowed = 31 secs
// it RARELY takes this long.
UInt32 milsSpent = 0; 

// wait for a not busy bus
// should be ready, but some devices may be slow to wake or spin up.
for( int loopMils = 0; milsSpent < 3100; loopMils++ )
{
	OSSynchronizeIO();
	status = *_tfStatusCmdReg;
	if( (status & mATABusy) == 0x00 )
		break;

	IOSleep( 10 );	
	milsSpent++;
}

// spun on BSY for too long, declare bus empty
if( ! (milsSpent < 3100) )
	goto AllDone;


// select each possible device on the bus, wait for BSY- 
// then check for protocol signatures.	

for( int unit = 0; unit < 2; unit++ )
{

	// wait for a not busy bus
	for( int loopMils = 0; milsSpent < 3100; loopMils++ )
	{
		// write the selection bit
		OSSynchronizeIO();
		*_tfSDHReg	= ( unit << 4 );
		IODelay( 10 );
		// typically, devices respond quickly to selection
		// but we'll give it a chance in case it is slow for some reason.
		status = *_tfStatusCmdReg;
		if( (status & mATABusy) == 0x00 )
		{	
			break;	
		}

		IOSleep( 10 );	
		milsSpent++;
	}

	// spun on BSY too long, probably bad device
	if( ! (milsSpent < 3100) )
		goto AllDone;

	// check for ATAPI device signature first
	if ( ( *_tfCylLoReg == 0x14) && ( *_tfCylHiReg == 0xEB) )
	{	
		if(	(unit == 1 )
			&& ( _devInfo[0].type == kATAPIDeviceType )  )
		{

		// OK we've met the condition for an indeterminate bus, master is atapi and we see a slave atapi
		// signature. This is legal ATA, though we are fortunate enough that most devices don't do this.

			if( ATAPISlaveExists( ) != true )
			{
				_devInfo[unit].type = kUnknownATADeviceType;
				goto AllDone;

			} 

		} 

		 _devInfo[unit].type = kATAPIDeviceType;
		 _devInfo[unit].packetSend = kATAPIDRQFast;  // this is the safest default setting
		unitsFound++;

	} // check for ATA signature, including status RDY=1 and ERR=0
	else if ( (*_tfCylLoReg == 0x00) && (*_tfCylHiReg == 0x00) &&
			  (*_tfSCountReg == 0x01) && (*_tfSectorNReg == 0x01) &&
			  ( (*_tfAltSDevCReg & 0x51) == 0x50) )
	{

		 _devInfo[unit].type = kATADeviceType;
		 _devInfo[unit].packetSend = kATAPIUnknown;  
		unitsFound++;

	}else{

		_devInfo[unit].type = kUnknownATADeviceType;
		_devInfo[unit].packetSend = kATAPIUnknown;  
	}

}

after:

	for( int i = 0; i < 100; i++)
{

	// read the status register - helps deal with devices which errantly 
	// set interrupt pending states during resets. Reset operations are not 
	// supposed to generate interrupts, but some devices do anyway.
	// interrupt handlers should be prepared to deal with errant interrupts on ATA busses.
	OSSynchronizeIO();
	UInt8 status = *_tfStatusCmdReg;	  

	// when drive is ready, break the loop
	if( ( status & readyMask )== readyOn)
	{
		// device reset completed in time
		resetFailed = false;
		break;
	}

	IOSleep( 10 );  // sleep thread for another 10 ms

}


if( resetFailed )
{
	// it is likely that this hardware is broken. 
	// There's no recovery action if the drive fails 
	// to reset.	
	DLOG("IOATA device failed to reset.\n");	
	result = kATATimeoutErr;
}

DLOG("IOATA reset complete.\n");

return result;

}


/*---------------------------------------------------------------------------
*
* Subclasses should take necessary action to create DMA channel programs, 
* for the current memory descriptor in _currentCommand and activate the 
* the DMA hardware
---------------------------------------------------------------------------*/
IOReturn
IOATAController::startDMA( void )
{


DLOG("IOATA Bus controllers that offer DMA must provide implementation/n");

return kATAModeNotSupported;
}




/*---------------------------------------------------------------------------
* Subclasses should take all actions necesary to safely shutdown DMA engines
* in any state of activity, whether finished, pending or stopped. Calling 
* this function must be harmless reguardless of the state of the engine.
*
---------------------------------------------------------------------------*/
IOReturn
IOATAController::stopDMA( void )
{

DLOG("IOATA Bus controllers that offer DMA must provide implementation/n");

return kATAModeNotSupported;
}


/*---------------------------------------------------------------------------
//	WaitForU8Status
//	Will wait up to one millisecond for the value in the altStatus register & mask to equal the value
//	passed in. Note that I always use the altStatus register so as not to have the side affect of clearing
//	the interrupt if there is one.
---------------------------------------------------------------------------*/
bool		
IOATAController::waitForU8Status (UInt8 mask, UInt8 value)
{
int	i;

// we will read the status from the alt status register so as not
// to clear the interrupt accidentally

for (i=0; i < kStatusDelayLoopMS; i++)
{
	OSSynchronizeIO();

	if ((*_tfAltSDevCReg & mask) == value)
	{
		return true;
	}

	IODelay( kStatusDelayTime );
}
return false;																	// time's up
}

/*----------------------------------------------------------------------------------------------------
**	Routine 	ATAPISlaveExists
**
**	Purpose:   Determines whether an ATAPI device seen as a "slave" of a master ATAPI device
**			   is actually present, or the product of the master shadowing a not-present slave's registers
**			   Call this function when the master device shows EBh 14h, and the slave also shows the ATAPI
**			   protocol signature.
**	Returns:   False if a device is ruled out. True if a device is verified. Leaves device in a ready state,
** 			   But no longer showing signatures. 

NOTE:	 Device 1 (slave) is assumed already selected.
*/


bool 
IOATAController::ATAPISlaveExists( void )
{
UInt8						scratchByte;
UInt16						scratchWord;
UInt32						dataCounter;
UInt32						loopCounter;

// The only option is to issue a command and see what happens.
OSSynchronizeIO();		
*_tfAltSDevCReg = 0x02; // disable interrupts

//issue INDENTIFY PACKET DEVICE 
OSSynchronizeIO();	
*_tfStatusCmdReg = 0xA1;  

// reading and disreguarding a register provides the required 400ns delay time.
OSSynchronizeIO();	
scratchByte = *_tfAltSDevCReg;

OSSynchronizeIO();	
scratchByte = *_tfAltSDevCReg;

// if the device returns status 00h, we declare it not present. A real device would probably be 
// status BSY (80h) now. An incredibly fast device might be ready to move data and show DRQ.
// However, by ATA standards, a not present device is required to return 00h.
// Lucky break, no device and we figured it out in a hurry.

if( (scratchByte == 0x00) )
{
	// enable device interrupt
	*_tfAltSDevCReg = 0x00;
	OSSynchronizeIO();
	return false;
}

// OK we probably have a device now. We have to wait for drive to send data, and read it and clear it.
// It is possible that the a misbehaving master has decided to respond to the command. So, we'll
// break on error bit and say it's not a real slave should that happen.

// take a leisurely approach, this will take a while.

// give the device up to 10 seconds to respond with data.
for( loopCounter = 0; loopCounter < 10000; loopCounter++)   
{		
	OSSynchronizeIO();
	scratchByte =  *_tfAltSDevCReg;

	// If drive sets error, clear status and return false. It's probably a misbehaving master
	if( scratchByte & 0x01 )
		break;		

	// this means the drive is really there. Clear the data and return true.
	if( (scratchByte & 0x58) == 0x58)  // RDY=1  DRQ=1
	{
		OSSynchronizeIO();
		scratchByte = *_tfStatusCmdReg; // clear pending interrupt state

		for( dataCounter = 0; dataCounter < 256; dataCounter++ )
		{
			OSSynchronizeIO();
			scratchWord = *_tfDataReg;
		}				
		// enable device interrupt
		*_tfAltSDevCReg = 0x00;
		OSSynchronizeIO();
		return true;		
	}

	// OK, sleep for 10 ms and try again.
	IOSleep(10);			
}

// In the ugly case, a drive set BSY, and didn't respond within 10 seconds with data.
// Otherwise, this is the for loop terminating on seeing the error bit.
// We'll read status and return false.

OSSynchronizeIO();
scratchByte = *_tfStatusCmdReg; // clear pending interrupt state	

// enable device interrupt
*_tfAltSDevCReg = 0x00;
OSSynchronizeIO();

return false;

}



/*---------------------------------------------------------------------------
*	scan the bus to see if devices are attached. The assumption is that the 
*  devices are in a cleanly-reset state, showing their protocol signatures, 
*  and the bus is properly wired with a pull down resistor on DD:7.
*	If your bus controller does not meet these conditions, you should override 
*	and supply your own function which meets your specific hardware needs.
*	Your controller may or may not require a reset, or it may require more 
*  thorough scanning, or additional configuration prior to looking for drives,
*	or it may aquire information from firmware indicating the devices attached.
*	This function should be self contained and not rely upon work loop or 
* 	or anything other than the register pointers being setup and enabled for access
---------------------------------------------------------------------------*/

UInt32 
IOATAController::scanForDrives( void )
{
UInt32 unitsFound = 0;
UInt8 status = 0x00;
// count total time spent searching max time allowed = 31 secs
// it RARELY takes this long.
UInt32 milsSpent = 0; 

// wait for a not busy bus
// should be ready, but some devices may be slow to wake or spin up.
for( int loopMils = 0; milsSpent < 100; loopMils++ )
{
	OSSynchronizeIO();
	status = *_tfStatusCmdReg;
	if( (status & mATABusy) == 0x00 )
		break;

	IOSleep( 10 );	
	milsSpent++;
}

// spun on BSY for too long, declare bus empty
if( ! (milsSpent < 100) )
	goto AllDone;


// select each possible device on the bus, wait for BSY- 
// then check for protocol signatures.	

for( int unit = 0; unit < 2; unit++ )
{

	// wait for a not busy bus
	for( int loopMils = 0; milsSpent < 100; loopMils++ )
	{
		// write the selection bit
		OSSynchronizeIO();
		*_tfSDHReg	= ( unit << 4 );
		IODelay( 10 );
		// typically, devices respond quickly to selection
		// but we'll give it a chance in case it is slow for some reason.
		status = *_tfStatusCmdReg;
		if( (status & mATABusy) == 0x00 )
		{	
			break;	
		}

		IOSleep( 10 );	
		milsSpent++;
	}

	// spun on BSY too long, probably bad device
	if( ! (milsSpent < 100) )
		goto AllDone;

	// check for ATAPI device signature first
	if ( ( *_tfCylLoReg == 0x14) && ( *_tfCylHiReg == 0xEB) )
	{	
		if(	(unit == 1 )
			&& ( _devInfo[0].type == kATAPIDeviceType )  )
		{

		// OK we've met the condition for an indeterminate bus, master is atapi and we see a slave atapi
		// signature. This is legal ATA, though we are fortunate enough that most devices don't do this.

			if( ATAPISlaveExists( ) != true )
			{
				_devInfo[unit].type = kUnknownATADeviceType;
				goto AllDone;

			} 

		} 

		 _devInfo[unit].type = kATAPIDeviceType;
		 _devInfo[unit].packetSend = kATAPIDRQFast;  // this is the safest default setting
		unitsFound++;

	} // check for ATA signature, including status RDY=1 and ERR=0
	else if ( (*_tfCylLoReg == 0x00) && (*_tfCylHiReg == 0x00) &&
			  (*_tfSCountReg == 0x01) && (*_tfSectorNReg == 0x01) &&
			  ( (*_tfAltSDevCReg & 0x51) == 0x50) )
	{

		 _devInfo[unit].type = kATADeviceType;
		 _devInfo[unit].packetSend = kATAPIUnknown;  
		unitsFound++;

	}else{

		_devInfo[unit].type = kUnknownATADeviceType;
		_devInfo[unit].packetSend = kATAPIUnknown;  
	}

}

Link to comment
Share on other sites

Problem. I get an error on shutdown.

 

Well this sweet action dropped my boot time to 28.6 Seconds from Post to Desktop but now when I shut down I get this error:

 

Break on __THE_PROCESS_HASFORKED_AND_YOCANNOT_USE_THIS_COREFOUNDATION_FUNCTIONALITY__YOU_

UST_EXEC__() to debug.

The process has forked and you cannot use this CoreFoundation functionality safely. You Must exec().

Link to comment
Share on other sites

 Share

×
×
  • Create New...