IOFireWireSBP2Login.cpp [plain text]
#include <IOKit/IOMessage.h>
#include <IOKit/sbp2/IOFireWireSBP2Login.h>
#include <IOKit/sbp2/IOFireWireSBP2LUN.h>
#include <IOKit/sbp2/IOFireWireSBP2Target.h>
#define FIREWIREPRIVATE
#include <IOKit/firewire/IOFireWireController.h>
#undef FIREWIREPRIVATE
#include <IOKit/firewire/IOConfigDirectory.h>
#include "FWDebugging.h"
#include "IOFireWireSBP2Diagnostics.h"
#include "IOFWSBP2PseudoAddressSpace.h"
#define kFetchAgentSplitTimeout (3*125*1000) // 275 milliseconds
#define kFetchAgentRetryInterval (125*1000) // 125 milliseconds
extern const OSSymbol *gUnit_Characteristics_Symbol;
extern const OSSymbol *gManagement_Agent_Offset_Symbol;
extern const OSSymbol *gFast_Start_Symbol;
OSDefineMetaClassAndStructors( IOFireWireSBP2Login, OSObject );
OSMetaClassDefineReservedUnused(IOFireWireSBP2Login, 0);
OSMetaClassDefineReservedUnused(IOFireWireSBP2Login, 1);
OSMetaClassDefineReservedUnused(IOFireWireSBP2Login, 2);
OSMetaClassDefineReservedUnused(IOFireWireSBP2Login, 3);
OSMetaClassDefineReservedUnused(IOFireWireSBP2Login, 4);
OSMetaClassDefineReservedUnused(IOFireWireSBP2Login, 5);
OSMetaClassDefineReservedUnused(IOFireWireSBP2Login, 6);
OSMetaClassDefineReservedUnused(IOFireWireSBP2Login, 7);
OSMetaClassDefineReservedUnused(IOFireWireSBP2Login, 8);
#if defined(__BIG_ENDIAN__)
#define SBP2SwapHostToBigInt32Array(array, bytes)
#define SBP2SwapBigToHostInt32Array(array, bytes)
#elif defined(__LITTLE_ENDIAN__)
static void SBP2SwapInt32Array(void * array, int bytes)
{
if ( array && bytes )
{
UInt32 * quads = (UInt32 *) array;
bytes >>= 2;
while (bytes--)
quads[bytes] = OSSwapInt32(quads[bytes]);
}
}
static inline void SBP2SwapHostToBigInt32Array(void * array, int bytes)
{ SBP2SwapInt32Array(array, bytes); }
static inline void SBP2SwapBigToHostInt32Array(void * array, int bytes)
{ SBP2SwapInt32Array(array, bytes); }
#else
#error Unknown endianess
#endif
#pragma mark -
bool IOFireWireSBP2Login::initWithLUN( IOFireWireSBP2LUN * lun )
{
IOReturn status = kIOReturnSuccess;
fLUN = lun;
fTarget = getTarget();
fUnit = fLUN->getFireWireUnit();
fControl = fUnit->getController();
fRefCon = NULL;
fLoginGeneration = 0;
fLoginNodeID = 0;
fLoginFlags = 0;
fMaxPayloadSize = 4;
fStatusBlockAddressSpace = NULL;
fStatusNotifyCallback = NULL;
fStatusNotifyRefCon = NULL;
fUnsolicitedStatusNotifyCallback = NULL;
fUnsolicitedStatusNotifyRefCon = NULL;
fLoginORBAddressSpace = NULL;
fLoginResponseAddressSpace = NULL;
fLoginTimeoutTimerSet = false;
fLoginWriteCommand = NULL;
fLoginWriteCommandMemory = NULL;
fLoginWriteInProgress = false;
fLoginCompletionCallback = NULL;
fLoginCompletionRefCon = NULL;
fReconnectORBAddressSpace = NULL;
fReconnectStatusBlockAddressSpace = NULL;
fReconnectTime = 0;
fReconnectTimeoutTimerSet = false;
fReconnectWriteCommand = NULL;
fReconnectWriteCommandMemory = NULL;
fReconnectWriteInProgress = false;
fReconnectWriteInterrupted = false;
fLogoutORBAddressSpace = NULL;
fLogoutTimeoutTimerSet = false;
fLogoutWriteInProgress = false;
fLogoutWriteCommand = NULL;
fLogoutWriteCommandMemory = NULL;
fLogoutCompletionCallback = NULL;
fLogoutCompletionRefCon = NULL;
fLoginRetryMax = 32;
fLoginRetryDelay = 1000000;
fUnsolicitedStatusEnableRequested = false;
fFetchAgentWriteCommandInUse = false;
fFetchAgentWriteCommand = NULL;
fFetchAgentWriteCommandMemory = NULL;
fFetchAgentWriteCompletion = NULL;
fFetchAgentResetInProgress = false;
fFetchAgentResetCommand = NULL;
fFetchAgentResetRefCon = NULL;
fFetchAgentResetCompletion = NULL;
fDoorbellInProgress = false;
fDoorbellRingAgain = false;
fDoorbellCommand = NULL;
fUnsolicitedStatusEnableInProgress = false;
fUnsolicitedStatusEnableCommand = NULL;
fSetBusyTimeoutBuffer = OSSwapHostToBigInt32(0x0000000f);
fSetBusyTimeoutInProgress = false;
fSetBusyTimeoutAddress = FWAddress( 0x0000FFFF, 0xF0000210 );
fSetBusyTimeoutCommand = NULL;
fPasswordBuf = NULL;
fPasswordLen = 0;
fPasswordAddressSpace = NULL;
fPasswordAddress = NULL;
fPasswordDescriptor = NULL;
fSuspended = false;
fARDMAMax = 0;
fLastORBAddress = FWAddress(0,0);
IOWorkLoop * workLoop = NULL;
if( status == kIOReturnSuccess )
{
workLoop = fLUN->getWorkLoop();
if( !workLoop )
status = kIOReturnNoResources;
}
if( status == kIOReturnSuccess )
{
fGate = IOCommandGate::commandGate( this );
if( !fGate )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
workLoop->retain();
workLoop->addEventSource( fGate );
}
if( status == kIOReturnSuccess )
{
fLoginState = kLoginStateIdle;
status = getUnitInformation();
FWKLOG( ( "IOFireWireSBP2Login<%p> : fManagementOffset = 0x%lx, fMaxORBSize = %d, fMaxCommandBlockSize = %d\n", this, fManagementOffset, fMaxORBSize, fMaxCommandBlockSize ) );
}
if( status == kIOReturnSuccess )
{
status = allocateResources();
}
if( status == kIOReturnSuccess )
{
fORBSet = OSSet::withCapacity(1);
if( fORBSet == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
fORBSetIterator = OSCollectionIterator::withCollection( fORBSet );
}
if( status == kIOReturnSuccess )
{
OSObject * prop = fLUN->getProperty( "FWARDMAMax", gIOServicePlane );
if( prop != NULL )
{
fARDMAMax = ((OSNumber*)prop)->unsigned32BitValue();
}
}
return (status == kIOReturnSuccess);
}
IOReturn IOFireWireSBP2Login::getUnitInformation( void )
{
IOReturn status = kIOReturnSuccess;
UInt32 unitCharacteristics = 0;
OSObject * prop = NULL;
prop = fLUN->getProperty( gManagement_Agent_Offset_Symbol );
if( prop == NULL )
status = kIOReturnError;
if( status == kIOReturnSuccess )
{
fManagementOffset = ((OSNumber*)prop)->unsigned32BitValue();
}
FWKLOG( ("IOFireWireSBP2Login<%p> : status = %d, fManagementOffset = %d\n", this, status, fManagementOffset) );
if( status == kIOReturnSuccess )
{
prop = fLUN->getProperty( gUnit_Characteristics_Symbol );
if( prop == NULL )
status = kIOReturnError;
}
if( status == kIOReturnSuccess )
{
unitCharacteristics = ((OSNumber*)prop)->unsigned32BitValue();
fManagementTimeout = ((unitCharacteristics >> 8) & 0xff) * 500; UInt32 orbSize = (unitCharacteristics & 0xff) * 4;
if( orbSize < 32 )
orbSize = 32;
fMaxORBSize = orbSize;
fMaxCommandBlockSize = orbSize - (sizeof(IOFireWireSBP2ORB::FWSBP2ORB) - 4);
}
if( status == kIOReturnSuccess )
{
prop = fLUN->getProperty( gFast_Start_Symbol );
if( prop != NULL )
{
UInt32 fastStartInfo = ((OSNumber*)prop)->unsigned32BitValue();
fFastStartSupported = true;
fFastStartOffset = fastStartInfo & 0x000000ff;
fFastStartMaxPayload = (fastStartInfo >> 8) & 0x000000ff;
}
}
FWKLOG( ("IOFireWireSBP2Login<%p> : fFastStartSupported = %d, fFastStartOffset = 0x%02lx, fFastStartMaxPayload = %d\n", this, fFastStartSupported, fFastStartOffset, fFastStartMaxPayload ) );
return status;
}
IOReturn IOFireWireSBP2Login::allocateResources( void )
{
IOReturn status = kIOReturnSuccess;
FWAddress host_address;
if( status == kIOReturnSuccess )
{
fLoginORBAddressSpace = IOFWSBP2PseudoAddressSpace::simpleRead( fControl, &host_address, sizeof(FWSBP2LoginORB), &fLoginORB );
if ( fLoginORBAddressSpace == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
fLoginORBAddress.nodeID = OSSwapHostToBigInt16( host_address.nodeID );
fLoginORBAddress.addressHi = OSSwapHostToBigInt16( host_address.addressHi );
fLoginORBAddress.addressLo = OSSwapHostToBigInt32( host_address.addressLo );
status = fLoginORBAddressSpace->activate();
}
if( status == kIOReturnSuccess )
{
fLoginResponseAddressSpace = IOFWSBP2PseudoAddressSpace::simpleRW( fControl, &fLoginResponseAddress,
sizeof(FWSBP2LoginResponse),
&fLoginResponse );
if ( fLoginResponseAddressSpace == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
status = fLoginResponseAddressSpace->activate();
}
if( status == kIOReturnSuccess )
{
fReconnectORBAddressSpace = IOFWPseudoAddressSpace::simpleRead( fControl, &host_address,
sizeof(FWSBP2ReconnectORB),
&fReconnectORB );
if ( fReconnectORBAddressSpace == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
fReconnectORBAddress.nodeID = OSSwapHostToBigInt16( host_address.nodeID );
fReconnectORBAddress.addressHi = OSSwapHostToBigInt16( host_address.addressHi );
fReconnectORBAddress.addressLo = OSSwapHostToBigInt32( host_address.addressLo );
status = fReconnectORBAddressSpace->activate();
}
if( status == kIOReturnSuccess )
{
fStatusBlockAddressSpace = fUnit->createPseudoAddressSpace( &fStatusBlockAddress,
sizeof(FWSBP2StatusBlock),
NULL,
IOFireWireSBP2Login::statusBlockWriteStatic,
this );
if ( fStatusBlockAddressSpace == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
status = fStatusBlockAddressSpace->activate();
}
if( status == kIOReturnSuccess )
{
fReconnectStatusBlockAddressSpace =
fUnit->createPseudoAddressSpace( &fReconnectStatusBlockAddress, sizeof(FWSBP2StatusBlock),
NULL, IOFireWireSBP2Login::reconnectStatusBlockWriteStatic, this );
if ( fReconnectStatusBlockAddressSpace == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
status = fReconnectStatusBlockAddressSpace->activate();
}
if( status == kIOReturnSuccess )
{
fLogoutORBAddressSpace = IOFWPseudoAddressSpace::simpleRead( fControl, &host_address, sizeof(FWSBP2LogoutORB),
&fLogoutORB );
if ( fLogoutORBAddressSpace == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
fLogoutORBAddress.nodeID = OSSwapHostToBigInt16( host_address.nodeID );
fLogoutORBAddress.addressHi = OSSwapHostToBigInt16( host_address.addressHi );
fLogoutORBAddress.addressLo = OSSwapHostToBigInt32( host_address.addressLo );
status = fLogoutORBAddressSpace->activate();
}
fLoginORB.loginResponseAddressHi = OSSwapHostToBigInt32((fLoginResponseAddress.nodeID << 16) | fLoginResponseAddress.addressHi);
fLoginORB.loginResponseAddressLo = OSSwapHostToBigInt32(fLoginResponseAddress.addressLo);
fLoginORB.loginResponseLength = OSSwapHostToBigInt16(sizeof( FWSBP2LoginResponse ));
fLoginORB.lun = OSSwapHostToBigInt16(fLUN->getLUNumber());
FWKLOG( ("IOFireWireSBP2Login<%p>::allocateResources lun number = %d\n", this, OSSwapBigToHostInt16(fLoginORB.lun)) );
fLoginORB.statusFIFOAddressHi = OSSwapHostToBigInt32((fStatusBlockAddress.nodeID << 16) | fStatusBlockAddress.addressHi);
fLoginORB.statusFIFOAddressLo = OSSwapHostToBigInt32(fStatusBlockAddress.addressLo);
fReconnectORB.options = OSSwapHostToBigInt16(3 | 0x8000); fReconnectORB.statusFIFOAddressHi = OSSwapHostToBigInt32((fReconnectStatusBlockAddress.nodeID << 16) | fReconnectStatusBlockAddress.addressHi);
fReconnectORB.statusFIFOAddressLo = OSSwapHostToBigInt32(fReconnectStatusBlockAddress.addressLo);
fLogoutORB.options = OSSwapHostToBigInt16(7 | 0x8000); fLogoutORB.statusFIFOAddressHi = OSSwapHostToBigInt32((fStatusBlockAddress.nodeID << 16) | fStatusBlockAddress.addressHi);
fLogoutORB.statusFIFOAddressLo = OSSwapHostToBigInt32(fStatusBlockAddress.addressLo);
if( status == kIOReturnSuccess )
{
fLoginWriteCommandMemory = IOMemoryDescriptor::withAddress( &fLoginORBAddress, 8, kIODirectionOut);
if( fLoginWriteCommandMemory == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
fLoginWriteCommand = fUnit->createWriteCommand( FWAddress(0x0000ffff, 0xf0000000 + (fManagementOffset << 2)),
fLoginWriteCommandMemory,
IOFireWireSBP2Login::loginWriteCompleteStatic, this, true );
if( fLoginWriteCommand == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
fLoginTimeoutCommand = fControl->createDelayedCmd( fManagementTimeout * 1000,
IOFireWireSBP2Login::loginTimeoutStatic, this);
}
if( status == kIOReturnSuccess )
{
fLoginRetryTimeoutCommand = fControl->createDelayedCmd( 1000000, IOFireWireSBP2Login::loginRetryTimeoutStatic, this);
}
if( status == kIOReturnSuccess )
{
fReconnectRetryTimeoutCommand = fControl->createDelayedCmd( 100000, IOFireWireSBP2Login::reconnectRetryTimeoutStatic, this);
}
if( status == kIOReturnSuccess )
{
fReconnectWriteCommandMemory = IOMemoryDescriptor::withAddress( &fReconnectORBAddress, 8, kIODirectionOut);
if( fReconnectWriteCommandMemory == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
fReconnectWriteCommand = fUnit->createWriteCommand( FWAddress(0x0000ffff, 0xf0000000 + (fManagementOffset << 2)),
fReconnectWriteCommandMemory,
IOFireWireSBP2Login::reconnectWriteCompleteStatic, this, true );
if( fReconnectWriteCommand == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
fReconnectTimeoutCommand = (IOFWDelayCommand*)fControl->createDelayedCmd( ((fManagementTimeout + 1000) * 1000),
IOFireWireSBP2Login::reconnectTimeoutStatic, this);
if( !fReconnectTimeoutCommand )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
fLogoutWriteCommandMemory = IOMemoryDescriptor::withAddress( &fLogoutORBAddress, 8, kIODirectionOut);
if( fLogoutWriteCommandMemory == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
fLogoutWriteCommand = fUnit->createWriteCommand( FWAddress(0x0000ffff, 0xf0000000 + (fManagementOffset << 2)),
fLogoutWriteCommandMemory,
IOFireWireSBP2Login::logoutWriteCompleteStatic, this, true );
if( fLogoutWriteCommand == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
fLogoutTimeoutCommand = fControl->createDelayedCmd( fManagementTimeout * 1000,
IOFireWireSBP2Login::logoutTimeoutStatic, this);
}
if( status == kIOReturnSuccess )
{
fFetchAgentRetryTimerCommand = fControl->createDelayedCmd( kFetchAgentRetryInterval,
IOFireWireSBP2Login::fetchAgentRetryTimerStatic, this);
}
if( fFastStartSupported )
{
if( status == kIOReturnSuccess )
{
UInt32 size = fFastStartMaxPayload * 4;
if( size == 0 )
size = 4096;
fFetchAgentWriteCommandMemory = IOBufferMemoryDescriptor::withOptions( kIODirectionOutIn | kIOMemoryUnshared, size, PAGE_SIZE );
if( fFetchAgentWriteCommandMemory == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
fFetchAgentWriteCommand = fUnit->createWriteCommand( FWAddress(0,0), fFetchAgentWriteCommandMemory,
IOFireWireSBP2Login::fetchAgentWriteCompleteStatic, this, true );
if( fFetchAgentWriteCommand == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
fFetchAgentWriteCommand->setTimeout( kFetchAgentSplitTimeout );
fFetchAgentWriteCommand->setRetries( 0 );
}
}
else
{
if( status == kIOReturnSuccess )
{
fFetchAgentWriteCommandMemory = IOMemoryDescriptor::withAddress( &fLastORBAddress, 8, kIODirectionOut );
if( fFetchAgentWriteCommandMemory == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
fFetchAgentWriteCommand = fUnit->createWriteCommand( FWAddress(0,0), fFetchAgentWriteCommandMemory,
IOFireWireSBP2Login::fetchAgentWriteCompleteStatic, this, true );
if( fFetchAgentWriteCommand == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
fFetchAgentWriteCommand->setTimeout( kFetchAgentSplitTimeout );
fFetchAgentWriteCommand->setRetries( 0 );
}
}
if( status == kIOReturnSuccess )
{
fFetchAgentResetCommand = fUnit->createWriteQuadCommand( FWAddress(0,0), &fFetchAgentResetBuffer, 1,
IOFireWireSBP2Login::fetchAgentResetCompleteStatic,
this, true );
if( fFetchAgentResetCommand == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
fDoorbellCommand = fUnit->createWriteQuadCommand( FWAddress(0,0), &fDoorbellBuffer, 1,
IOFireWireSBP2Login::doorbellCompleteStatic,
this, true );
if( fDoorbellCommand == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
fSetBusyTimeoutCommand = fUnit->createWriteQuadCommand( fSetBusyTimeoutAddress,
&fSetBusyTimeoutBuffer, 1,
IOFireWireSBP2Login::setBusyTimeoutCompleteStatic,
this, true );
if( fSetBusyTimeoutCommand == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
fUnsolicitedStatusEnableCommand = fUnit->createWriteQuadCommand( FWAddress(0,0), &fUnsolicitedStatusEnableBuffer, 1,
IOFireWireSBP2Login::unsolicitedStatusEnableCompleteStatic,
this, true );
if( fUnsolicitedStatusEnableCommand == NULL )
status = kIOReturnNoMemory;
}
return status;
}
void IOFireWireSBP2Login::release() const
{
if( getRetainCount() >= 2 )
OSObject::release(2);
}
void IOFireWireSBP2Login::free( void )
{
IOReturn status = kIOReturnSuccess;
FWKLOG( ( "IOFireWireSBP2Login<%p> : free called\n", this ) );
if( fControl && fTarget )
{
fControl->closeGate();
if( fReconnectWriteCommand )
{
fTarget->cancelMgmtAgentAccess( fReconnectWriteCommand );
}
if( fLoginWriteCommand )
{
fTarget->cancelMgmtAgentAccess( fLoginWriteCommand );
}
fControl->openGate();
}
removeLogin();
if( fFetchAgentResetInProgress )
fFetchAgentResetCommand->cancel( kIOReturnAborted );
if( fFetchAgentResetCommand )
fFetchAgentResetCommand->release();
if( fDoorbellInProgress )
fDoorbellCommand->cancel( kIOReturnAborted );
if( fDoorbellCommand )
fDoorbellCommand->release();
if( fUnsolicitedStatusEnableInProgress )
fUnsolicitedStatusEnableCommand->cancel( kIOReturnAborted );
if( fUnsolicitedStatusEnableCommand )
fUnsolicitedStatusEnableCommand->release();
if( fSetBusyTimeoutInProgress )
fSetBusyTimeoutCommand->cancel( kIOReturnAborted );
if( fSetBusyTimeoutCommand )
fSetBusyTimeoutCommand->release();
if( fLoginWriteInProgress )
fLoginWriteCommand->cancel( kIOReturnAborted );
if( fLoginWriteCommand != NULL )
fLoginWriteCommand->release();
if( fLoginWriteCommandMemory != NULL )
fLoginWriteCommandMemory->release();
if( fLoginTimeoutTimerSet )
fLoginTimeoutCommand->cancel(kIOReturnAborted);
if( fLoginTimeoutCommand )
fLoginTimeoutCommand->release();
stopLoginRetryTimer();
if( fLoginRetryTimeoutCommand )
fLoginRetryTimeoutCommand->release();
stopReconnectRetryTimer();
if( fReconnectRetryTimeoutCommand )
fReconnectRetryTimeoutCommand->release();
if( fLoginORBAddressSpace != NULL && status == kIOReturnSuccess )
{
fLoginORBAddressSpace->deactivate();
fLoginORBAddressSpace->release();
}
if( fLoginResponseAddressSpace != NULL && status == kIOReturnSuccess )
{
fLoginResponseAddressSpace->deactivate();
fLoginResponseAddressSpace->release();
}
if( fReconnectWriteInProgress )
fReconnectWriteCommand->cancel(kIOReturnAborted);
if( fReconnectWriteCommand != NULL )
fReconnectWriteCommand->release();
if( fReconnectWriteCommandMemory != NULL )
fReconnectWriteCommandMemory->release();
if( fReconnectTimeoutTimerSet )
fReconnectTimeoutCommand->cancel(kIOReturnAborted);
if( fReconnectTimeoutCommand )
fReconnectTimeoutCommand->release();
if( fReconnectORBAddressSpace != NULL && status == kIOReturnSuccess )
{
fReconnectORBAddressSpace->deactivate();
fReconnectORBAddressSpace->release();
}
if( fReconnectStatusBlockAddressSpace != NULL && status == kIOReturnSuccess )
{
fReconnectStatusBlockAddressSpace->deactivate();
fReconnectStatusBlockAddressSpace->release();
}
if( fLogoutWriteInProgress )
fLogoutWriteCommand->cancel(kIOReturnAborted);
if( fLogoutWriteCommand != NULL )
fLogoutWriteCommand->release();
if( fLogoutWriteCommandMemory != NULL )
fLogoutWriteCommandMemory->release();
if( fLogoutTimeoutTimerSet )
fLogoutTimeoutCommand->cancel(kIOReturnAborted);
if( fLogoutTimeoutCommand )
fLogoutTimeoutCommand->release();
if( fLogoutORBAddressSpace != NULL && status == kIOReturnSuccess )
{
fLogoutORBAddressSpace->deactivate();
fLogoutORBAddressSpace->release();
}
stopFetchAgentRetryTimer();
if( fFetchAgentRetryTimerCommand )
{
fFetchAgentRetryTimerCommand->release();
fFetchAgentRetryTimerCommand = NULL;
}
if( fFetchAgentWriteCommandInUse )
{
fFetchAgentWriteCommand->cancel(kIOReturnAborted);
}
if( fFetchAgentWriteCommand != NULL )
{
fFetchAgentWriteCommand->release();
fFetchAgentWriteCommand = NULL;
}
if( fFetchAgentWriteCommandMemory != NULL )
{
fFetchAgentWriteCommandMemory->release();
fFetchAgentWriteCommandMemory = NULL;
}
if( fStatusBlockAddressSpace != NULL && status == kIOReturnSuccess )
{
fStatusBlockAddressSpace->deactivate();
fStatusBlockAddressSpace->release();
}
if( fPasswordAddressSpace != NULL )
{
fPasswordAddressSpace->deactivate();
fPasswordAddressSpace->release();
fPasswordBuf = NULL;
fPasswordLen = 0;
}
if( fPasswordDescriptor != NULL )
{
fPasswordDescriptor->release();
fPasswordDescriptor = NULL;
}
if( fORBSetIterator )
{
IOFireWireSBP2ORB * item = NULL;
do
{
fORBSetIterator->reset();
item = (IOFireWireSBP2ORB *)fORBSetIterator->getNextObject();
if( item )
item->release();
} while( item );
fORBSetIterator->release();
}
if( fORBSet )
fORBSet->release();
for( int i = 0; i < fCriticalSectionCount; i++ )
{
fTarget->endIOCriticalSection();
}
if( fGate != NULL )
{
IOWorkLoop * workLoop = NULL;
workLoop = fGate->getWorkLoop();
workLoop->removeEventSource( fGate );
workLoop->release();
fGate->release();
fGate = NULL;
}
OSObject::free();
}
#pragma mark -
IOFireWireUnit * IOFireWireSBP2Login::getFireWireUnit( void )
{
return fUnit;
}
IOFireWireSBP2LUN * IOFireWireSBP2Login::getFireWireLUN( void )
{
return fLUN;
}
UInt32 IOFireWireSBP2Login::getMaxCommandBlockSize( void )
{
return fMaxCommandBlockSize;
}
UInt32 IOFireWireSBP2Login::getLoginID( void )
{
return fLoginID;
}
void IOFireWireSBP2Login::setRefCon( void * refCon )
{
fRefCon = refCon;
}
void * IOFireWireSBP2Login::getRefCon( void )
{
return fRefCon;
}
void IOFireWireSBP2Login::setLoginFlags( UInt32 loginFlags )
{
fLoginFlags = loginFlags;
FWKLOG(( "IOFireWireSBP2Login<%p> : setLoginFlags : 0x%08lx\n", this, fLoginFlags ));
}
UInt32 IOFireWireSBP2Login::getLoginFlags( void )
{
return fLoginFlags;
}
void IOFireWireSBP2Login::setLoginCompletion( void * refCon, FWSBP2LoginCallback completion )
{
fLoginCompletionRefCon = refCon;
fLoginCompletionCallback = completion;
}
void IOFireWireSBP2Login::setLogoutCompletion( void * refCon, FWSBP2LogoutCallback completion )
{
fLogoutCompletionRefCon = refCon;
fLogoutCompletionCallback = completion;
}
void IOFireWireSBP2Login::setReconnectTime( UInt32 reconnectTime )
{
fReconnectTime = reconnectTime & 0x0000000f;
}
UInt32 IOFireWireSBP2Login::getReconnectTime( void )
{
return fReconnectTime;
}
void IOFireWireSBP2Login::setStatusNotifyProc( void * refCon, FWSBP2NotifyCallback callback )
{
fStatusNotifyCallback = callback;
fStatusNotifyRefCon = refCon;
}
void IOFireWireSBP2Login::getStatusNotifyProc( void ** refCon, FWSBP2NotifyCallback * callback )
{
*callback = fStatusNotifyCallback;
*refCon = fStatusNotifyRefCon;
}
void IOFireWireSBP2Login::setUnsolicitedStatusNotifyProc( void * refCon, FWSBP2NotifyCallback callback )
{
fUnsolicitedStatusNotifyCallback = callback;
fUnsolicitedStatusNotifyRefCon = refCon;
}
void IOFireWireSBP2Login::getUnsolicitedStatusNotifyProc( void ** refCon, FWSBP2NotifyCallback * callback )
{
*callback = fStatusNotifyCallback;
*refCon = fStatusNotifyRefCon;
}
void IOFireWireSBP2Login::setMaxPayloadSize( UInt32 maxPayloadSize )
{
fMaxPayloadSize = maxPayloadSize;
}
UInt32 IOFireWireSBP2Login::getMaxPayloadSize( void )
{
return fMaxPayloadSize;
}
void IOFireWireSBP2Login::setLoginRetryCountAndDelayTime( UInt32 retryCount, UInt32 uSecs )
{
fLoginRetryMax = retryCount;
fLoginRetryDelay = uSecs;
if( fLoginRetryTimeoutCommand )
{
fLoginRetryTimeoutCommand->reinit( fLoginRetryDelay, IOFireWireSBP2Login::loginRetryTimeoutStatic, this );
}
}
IOReturn IOFireWireSBP2Login::setPassword( IOMemoryDescriptor * memory )
{
IOReturn status = kIOReturnSuccess;
IOByteCount len = 0;
if( fPasswordAddressSpace != NULL )
{
fPasswordAddressSpace->deactivate();
fPasswordAddressSpace->release();
fPasswordBuf = NULL;
fPasswordLen = 0;
}
if( fPasswordDescriptor != NULL )
{
fPasswordDescriptor->release();
fPasswordDescriptor = NULL;
}
if( status == kIOReturnSuccess )
{
fPasswordDescriptor = memory;
if( memory == NULL )
status = kIOReturnError;
}
if( status == kIOReturnSuccess )
{
fPasswordDescriptor->retain();
len = fPasswordDescriptor->getLength();
status = fPasswordDescriptor->prepare(); }
if( status == kIOReturnSuccess )
{
if( len <= 8 )
{
fLoginORB.password[0] = 0;
fLoginORB.password[1] = 0;
fLoginORB.passwordLength = 0;
status = memory->readBytes( 0, &(fLoginORB.password), len );
}
else
{
if( status == kIOReturnSuccess )
{
fPasswordAddressSpace = IOFWPseudoAddressSpace::simpleRW( fControl, &fPasswordAddress, memory );
if( fPasswordAddressSpace == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
status = fPasswordAddressSpace->activate();
}
if( status == kIOReturnSuccess )
{
fLoginORB.passwordLength = OSSwapHostToBigInt16(len);
fLoginORB.password[0] = OSSwapHostToBigInt32(0x0000ffff & fPasswordAddress.addressHi);
fLoginORB.password[1] = OSSwapHostToBigInt32(fPasswordAddress.addressLo);
}
}
}
return status;
}
IOReturn IOFireWireSBP2Login::setPassword( void * buf, UInt32 len )
{
IOReturn status = kIOReturnSuccess;
if( fPasswordAddressSpace != NULL )
{
fPasswordAddressSpace->deactivate();
fPasswordAddressSpace->release();
fPasswordBuf = NULL;
fPasswordLen = 0;
}
if( fPasswordDescriptor != NULL )
{
fPasswordDescriptor->release();
fPasswordDescriptor = NULL;
}
if( len <= 8 )
{
fPasswordBuf = buf;
fPasswordLen = len;
fLoginORB.password[0] = 0;
fLoginORB.password[1] = 0;
bcopy( buf, &(fLoginORB.password), len );
fLoginORB.passwordLength = 0;
}
else
{
if( status == kIOReturnSuccess )
{
fPasswordAddressSpace = IOFWPseudoAddressSpace::simpleRW( fControl, &fPasswordAddress, len, buf );
if( fPasswordAddressSpace == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
status = fPasswordAddressSpace->activate();
}
if( status == kIOReturnSuccess )
{
fPasswordBuf = buf;
fPasswordLen = len;
fLoginORB.passwordLength = OSSwapHostToBigInt16(len);
fLoginORB.password[0] = OSSwapHostToBigInt32(0x0000ffff & fPasswordAddress.addressHi);
fLoginORB.password[1] = OSSwapHostToBigInt32(fPasswordAddress.addressLo);
}
}
return status;
}
void IOFireWireSBP2Login::setLoginGeneration( UInt32 generation )
{
fUserLoginGeneration = generation;
fUserLoginGenerationSet = true;
}
void IOFireWireSBP2Login::clearLoginGeneration( void )
{
fUserLoginGenerationSet = false;
}
#pragma mark -
IOReturn IOFireWireSBP2Login::submitLogin( void )
{
IOReturn status = kIOReturnSuccess;
status = fGate->runAction( staticExecuteLogin );
return status;
}
IOReturn IOFireWireSBP2Login::staticExecuteLogin( OSObject *self, void *, void *, void *, void * )
{
return ((IOFireWireSBP2Login *)self)->initialExecuteLogin();
}
IOReturn IOFireWireSBP2Login::initialExecuteLogin( void )
{
IOReturn status = kIOReturnSuccess;
if( fLoginState != kLoginStateIdle || fLoginRetryTimeoutTimerSet )
{
return kIOReturnExclusiveAccess;
}
fLoginRetryCount = fLoginRetryMax;
status = executeLogin();
if( status != kIOReturnSuccess &&
((status != kIOFireWireBusReset) || !fUserLoginGenerationSet) &&
fLoginRetryCount != 0 )
{
fLoginRetryCount--;
startLoginRetryTimer();
status = kIOReturnSuccess;
}
return status;
}
IOReturn IOFireWireSBP2Login::executeLogin( void )
{
IOReturn status = kIOReturnSuccess;
FWKLOG( ( "IOFireWireSBP2Login<%p> : executeLogin\n", this ) );
if( fSuspended )
{
return kIOFireWireBusReset;
}
if( fLoginState != kLoginStateIdle )
{
return kIOReturnExclusiveAccess;
}
fLoginState = kLoginStateLoggingIn;
fLastORB = NULL;
fLastORBAddress = FWAddress(0,0);
fLoginResponse.reserved = 0;
fLoginResponse.reconnectHold = 0;
FWKLOG(( "IOFireWireSBP2Login<%p> : fLoginFlags : 0x%08lx\n", this, fLoginFlags ));
fLoginORB.options = OSSwapHostToBigInt16(0x0000 | 0x8000); fLoginORB.options |= OSSwapHostToBigInt16(fReconnectTime << 4);
if( fLoginFlags & kFWSBP2ExclusiveLogin )
fLoginORB.options |= OSSwapHostToBigInt16(0x1000);
fLoginWriteCommand->reinit( FWAddress(0x0000ffff, 0xf0000000 + (fManagementOffset << 2)),
fLoginWriteCommandMemory, IOFireWireSBP2Login::loginWriteCompleteStatic,
this, true );
fUnit->getNodeIDGeneration(fLoginGeneration, fLoginNodeID, fLocalNodeID);
if( fUserLoginGenerationSet && fUserLoginGeneration != fLoginGeneration )
{
status = kIOFireWireBusReset;
}
if( status == kIOReturnSuccess )
{
fLoginWriteInProgress = true;
fLoginStatusReceived = false;
status = fTarget->beginIOCriticalSection();
}
if( status == kIOReturnSuccess )
{
fInCriticalSection = true;
fCriticalSectionCount++;
if( fLoginFlags & kFWSBP2DontSynchronizeMgmtAgent )
fLoginWriteCommand->submit();
else
fTarget->synchMgmtAgentAccess( fLoginWriteCommand );
}
if( status != kIOReturnSuccess )
{
fLoginWriteInProgress = false;
fLoginState = kLoginStateIdle;
}
return status;
}
void IOFireWireSBP2Login::loginWriteCompleteStatic( void *refcon, IOReturn status, IOFireWireNub *device,
IOFWCommand *fwCmd )
{
((IOFireWireSBP2Login*)refcon)->loginWriteComplete( status, device, fwCmd );
}
void IOFireWireSBP2Login::loginWriteComplete( IOReturn status, IOFireWireNub *device, IOFWCommand *fwCmd )
{
FWKLOG( ("IOFireWireSBP2Login<%p> : login write complete\n", this) );
fLoginWriteInProgress = false;
if( fLoginStatusReceived )
{
processLoginWrite();
}
else
{
if( status == kIOReturnSuccess )
{
fLoginTimeoutTimerSet = true;
if( fLoginTimeoutCommand->submit() != kIOReturnSuccess )
fLoginTimeoutTimerSet = false;
}
else
{
fLoginState = kLoginStateIdle;
completeLogin( status ); }
}
}
void IOFireWireSBP2Login::loginTimeoutStatic( void *refcon, IOReturn status,
IOFireWireBus *bus, IOFWBusCommand *fwCmd)
{
((IOFireWireSBP2Login*)refcon)->loginTimeout( status, bus, fwCmd );
}
void IOFireWireSBP2Login::loginTimeout( IOReturn status, IOFireWireBus *bus, IOFWBusCommand *fwCmd)
{
fLoginTimeoutTimerSet = false;
if( status != kIOReturnSuccess )
{
FWKLOG( ("IOFireWireSBP2Login<%p> : login timed out\n", this) );
fLoginState = kLoginStateIdle;
completeLogin( kIOReturnTimeout );
}
}
void IOFireWireSBP2Login::startLoginRetryTimer( void )
{
stopLoginRetryTimer();
fLoginRetryTimeoutTimerSet = true;
if( fLoginRetryTimeoutCommand->submit() != kIOReturnSuccess )
fLoginRetryTimeoutTimerSet = false;
}
void IOFireWireSBP2Login::stopLoginRetryTimer( void )
{
if( fLoginRetryTimeoutTimerSet )
fLoginRetryTimeoutCommand->cancel( kIOReturnAborted );
}
void IOFireWireSBP2Login::loginRetryTimeoutStatic( void *refcon, IOReturn status,
IOFireWireBus *bus, IOFWBusCommand *fwCmd)
{
((IOFireWireSBP2Login*)refcon)->loginRetryTimeout( status, bus, fwCmd );
}
void IOFireWireSBP2Login::loginRetryTimeout( IOReturn status, IOFireWireBus *bus, IOFWBusCommand *fwCmd)
{
fLoginRetryTimeoutTimerSet = false;
if( status == kIOReturnTimeout )
{
FWKLOG( ("IOFireWireSBP2Login<%p> : login retry timer fired\n", this) );
IOReturn login_status = executeLogin();
if( login_status != kIOReturnSuccess )
{
completeLogin( login_status );
}
}
}
void IOFireWireSBP2Login::abortLogin( void )
{
if( fLoginWriteInProgress )
fLoginWriteCommand->cancel( kIOReturnAborted );
if( fLoginTimeoutTimerSet )
fLoginTimeoutCommand->cancel( kIOReturnAborted );
fLoginState = kLoginStateIdle;
}
void IOFireWireSBP2Login::completeLogin( IOReturn state, const void *buf, UInt32 len, void * buf2 )
{
FWKLOG( ( "IOFireWireSBP2Login<%p> : completeLogin\n", this ) );
if( (fLoginFlags & kFWSBP2DontSynchronizeMgmtAgent) == 0 )
fTarget->completeMgmtAgentAccess( );
if( fInCriticalSection )
{
fInCriticalSection = false;
if( fCriticalSectionCount > 0 )
{
fCriticalSectionCount--;
}
fTarget->endIOCriticalSection();
}
if( (state != kIOReturnSuccess) &&
((state != kIOFireWireBusReset) || !fUserLoginGenerationSet) &&
(state != kIOReturnNotAttached) &&
(fLoginRetryCount != 0) )
{
fLoginRetryCount--;
startLoginRetryTimer();
}
else if( fLoginCompletionCallback != NULL )
{
FWSBP2LoginCompleteParams params;
if( fUnsolicitedStatusEnableRequested )
{
fUnsolicitedStatusEnableRequested = false;
executeUnsolicitedStatusEnable();
}
params.login = this;
params.generation = fLoginGeneration;
params.status = state;
params.loginResponse = (FWSBP2LoginResponsePtr)buf2;
params.statusBlock = (FWSBP2StatusBlock*)buf;
params.statusBlockLength = len;
(*fLoginCompletionCallback)(fLoginCompletionRefCon, ¶ms);
}
}
UInt32 IOFireWireSBP2Login::statusBlockWriteStatic(void *refcon, UInt16 nodeID, IOFWSpeed &speed,
FWAddress addr, UInt32 len, const void *buf, IOFWRequestRefCon lockRead)
{
return ((IOFireWireSBP2Login*)refcon)->statusBlockWrite( nodeID, speed, addr, len, buf, lockRead );
}
UInt32 IOFireWireSBP2Login::statusBlockWrite( UInt16 nodeID, IOFWSpeed &speed, FWAddress addr, UInt32 len,
const void *buf, IOFWRequestRefCon lockRead )
{
FWKLOG( ( "IOFireWireSBP2Login<%p> : status block write\n", this ) );
if( len < 8 )
{
return kFWResponseComplete;
}
bzero( &fStatusBlock, sizeof(fStatusBlock) );
if( len < sizeof(fStatusBlock) )
bcopy( buf, &fStatusBlock, len);
else
bcopy( buf, &fStatusBlock, sizeof(fStatusBlock));
const void * client_status_block = &fStatusBlock;
#if 0
FWSBP2StatusBlock host_status_block;
bzero( &host_status_block, sizeof(host_status_block) );
bcopy( &fStatusBlock, &host_status_block, sizeof(host_status_block));
host_status_block.orbOffsetHi = OSSwapBigToHostInt16(fStatusBlock.orbOffsetHi);
host_status_block.orbOffsetLo = OSSwapBigToHostInt32(fStatusBlock.orbOffsetLo);
SBP2SwapBigToHostInt32Array( &host_status_block.status, sizeof(host_status_block.status) );
client_status_block = &host_status_block;
#endif
switch( fLoginState )
{
case kLoginStateLoggingIn:
if( fLoginTimeoutTimerSet )
{
fLoginTimeoutCommand->cancel(kIOReturnSuccess);
}
if( !fLoginStatusReceived )
{
bzero( &fLoginStatusBlock, sizeof(fLoginStatusBlock) );
if( len < sizeof(fLoginStatusBlock) )
bcopy( buf, &fLoginStatusBlock, len);
else
bcopy( buf, &fLoginStatusBlock, sizeof(fLoginStatusBlock));
fLoginStatusBlockLen = len;
if( fLoginWriteInProgress )
{
fLoginStatusReceived = true;
}
else
{
processLoginWrite();
}
}
break;
case kLoginStateConnected:
if( (fStatusBlock.details & 0xc0) == 0x80 )
{
if( fUnsolicitedStatusNotifyCallback != NULL )
{
FWSBP2NotifyParams params;
params.message = client_status_block;
params.length = len;
params.notificationEvent = kFWSBP2UnsolicitedStatus;
params.generation = fLoginGeneration;
(*fUnsolicitedStatusNotifyCallback)(fUnsolicitedStatusNotifyRefCon, ¶ms );
}
}
else
{
bool found = false;
FWAddress notificationAddress;
notificationAddress.nodeID = 0x0000;
notificationAddress.addressHi = OSSwapBigToHostInt16(fStatusBlock.orbOffsetHi);
notificationAddress.addressLo = OSSwapBigToHostInt32(fStatusBlock.orbOffsetLo);
IOFireWireSBP2ORB * item = NULL;
fORBSetIterator->reset();
while( (found != true) && (item = (IOFireWireSBP2ORB *) fORBSetIterator->getNextObject()) )
{
FWAddress address;
item->getORBAddress( &address );
if( (notificationAddress.addressHi & 0x0000ffff) == (address.addressHi & 0x0000ffff) &&
notificationAddress.addressLo == address.addressLo )
{
found = true;
}
}
FWKLOG( ( "IOFireWireSBP2Login<%p> : solicited found = %d\n", this, found ) );
bool deadBitIsSet = fStatusBlock.details & 0x08;
if( found )
{
UInt32 flags = item->getCommandFlags();
if( isORBTimerSet( item ) )
{
cancelORBTimer( item);
if( isORBAppended( item ) )
{
setORBIsAppended( item, false );
if( fCriticalSectionCount > 0 )
{
fCriticalSectionCount--;
}
fTarget->endIOCriticalSection();
}
}
else if( flags & kFWSBP2CommandCompleteNotify )
{
break;
}
if( fStatusNotifyCallback != NULL )
{
FWSBP2NotifyParams params;
params.message = client_status_block;
params.length = len;
params.notificationEvent = kFWSBP2NormalCommandStatus;
params.generation = fLoginGeneration;
params.commandObject = item;
(*fStatusNotifyCallback)(fStatusNotifyRefCon, ¶ms );
}
}
if( deadBitIsSet )
{
clearAllTasksInSet();
}
}
break;
case kLoginStateLoggingOut:
if( fLogoutTimeoutTimerSet )
{
fLogoutTimeoutCommand->cancel(kIOReturnSuccess);
}
if( ((fStatusBlock.details >> 4) & 3) == kFWSBP2RequestComplete &&
fStatusBlock.sbpStatus == kFWSBP2NoSense )
{
FWKLOG( ( "IOFireWireSBP2Login<%p> : successful logout\n", this ) );
fLoginState = kLoginStateIdle;
fUnsolicitedStatusEnableRequested = false;
fLoginID = OSSwapBigToHostInt16(fLoginResponse.loginID);
completeLogout( kIOReturnSuccess, client_status_block, len );
}
else
{
FWKLOG( ( "IOFireWireSBP2Login<%p> : logout failed!?\n", this ) );
fLoginState = kLoginStateIdle;
completeLogout( kIOReturnError, client_status_block, len );
}
clearAllTasksInSet();
break;
case kLoginStateReconnect:
case kLoginStateIdle:
default:
FWKLOG( ( "IOFireWireSBP2Login<%p> : status block write on illegal state\n", this ) );
break;
}
return kFWResponseComplete;
}
void IOFireWireSBP2Login::processLoginWrite( void )
{
if( ((fLoginStatusBlock.details >> 4) & 3) == kFWSBP2RequestComplete &&
fLoginStatusBlock.sbpStatus == kFWSBP2NoSense )
{
FWKLOG( ( "IOFireWireSBP2Login<%p> : successful login\n", this ) );
fLoginID = OSSwapBigToHostInt16(fLoginResponse.loginID);
fReconnectORB.loginID = OSSwapHostToBigInt16(fLoginID);
if( OSSwapBigToHostInt16(fLoginResponse.length) >= 16 )
fReconnectHold = (OSSwapBigToHostInt16(fLoginResponse.reconnectHold) & 0x7fff) + 1;
else
fReconnectHold = 1;
UInt32 commandBlockAgentAddressHi = OSSwapBigToHostInt32(fLoginResponse.commandBlockAgentAddressHi);
UInt32 commandBlockAgentAddressLo = OSSwapBigToHostInt32(fLoginResponse.commandBlockAgentAddressLo);
fFetchAgentResetAddress = FWAddress( commandBlockAgentAddressHi & 0x0000ffff,
commandBlockAgentAddressLo + 0x00000004 );
fFetchAgentResetCommand->reinit( fFetchAgentResetAddress,
&fFetchAgentResetBuffer, 1,
IOFireWireSBP2Login::fetchAgentResetCompleteStatic,
this, true );
fFetchAgentResetCommand->updateNodeID( fLoginGeneration, fLoginNodeID );
if( fFastStartSupported )
{
fFetchAgentAddress = FWAddress( commandBlockAgentAddressHi & 0x0000ffff,
commandBlockAgentAddressLo + (fFastStartOffset << 2));
}
else
{
fFetchAgentAddress = FWAddress( commandBlockAgentAddressHi & 0x0000ffff,
commandBlockAgentAddressLo + 0x00000008);
}
fFetchAgentWriteCommand->reinit( fFetchAgentAddress, fFetchAgentWriteCommandMemory,
IOFireWireSBP2Login::fetchAgentWriteCompleteStatic, this, true );
fFetchAgentWriteCommand->updateNodeID( fLoginGeneration, fLoginNodeID );
fFetchAgentWriteCommand->setRetries( 0 );
fDoorbellAddress = FWAddress( commandBlockAgentAddressHi & 0x0000ffff,
commandBlockAgentAddressLo + 0x00000010 );
fDoorbellCommand->reinit( fDoorbellAddress,
&fDoorbellBuffer, 1,
IOFireWireSBP2Login::doorbellCompleteStatic,
this, true );
fDoorbellCommand->updateNodeID( fLoginGeneration, fLoginNodeID );
fUnsolicitedStatusEnableAddress = FWAddress( commandBlockAgentAddressHi & 0x0000ffff,
commandBlockAgentAddressLo + 0x00000014 );
fUnsolicitedStatusEnableCommand->reinit( fUnsolicitedStatusEnableAddress,
&fUnsolicitedStatusEnableBuffer, 1,
IOFireWireSBP2Login::unsolicitedStatusEnableCompleteStatic,
this, true );
fUnsolicitedStatusEnableCommand->updateNodeID( fLoginGeneration, fLoginNodeID );
fLoginState = kLoginStateConnected;
completeLogin( kIOReturnSuccess, &fLoginStatusBlock, fLoginStatusBlockLen, &fLoginResponse );
}
else
{
FWKLOG( ( "IOFireWireSBP2Login<%p> : login failed\n", this ) );
fLoginState = kLoginStateIdle;
completeLogin( kIOReturnError, &fLoginStatusBlock, fLoginStatusBlockLen, NULL );
}
}
#pragma mark -
void IOFireWireSBP2Login::suspendedNotify( void )
{
FWKLOG( ( "IOFireWireSBP2Login<%p> : suspendedNotify\n", this ) );
fSuspended = true;
UInt32 generation = fControl->getGeneration();
stopFetchAgentRetryTimer();
switch( fLoginState )
{
case kLoginStateConnected:
startReconnectTimer();
break;
case kLoginStateReconnect:
stopReconnectRetryTimer();
startReconnectTimer();
break;
case kLoginStateLoggingIn:
if( fLoginGeneration != generation )
{
abortLogin();
}
break;
case kLoginStateIdle:
case kLoginStateLoggingOut:
default:
FWKLOG( ("IOFireWireSBP2Login<%p> : suspended notify, nothing to do\n", this) );
break;
}
}
void IOFireWireSBP2Login::resumeNotify( void )
{
FWKLOG( ( "IOFireWireSBP2Login<%p> : resume notify\n", this ) );
UInt32 generation = fControl->getGeneration();
fPhysicalAccessEnabled = fUnit->isPhysicalAccessEnabled();
fSuspended = false;
executeSetBusyTimeout();
if( fLogoutPending )
{
fLogoutPending = false;
executeLogout();
}
else
{
switch( fLoginState )
{
case kLoginStateReconnect:
if( fLoginGeneration != generation )
{
restartReconnect();
}
else
{
fLoginState = kLoginStateConnected;
if( fReconnectTimeoutTimerSet )
fReconnectTimeoutCommand->cancel(kIOReturnAborted);
}
break;
case kLoginStateLoggingIn:
if( fLoginGeneration != generation)
{
abortLogin();
}
break;
case kLoginStateIdle:
case kLoginStateLoggingOut:
case kLoginStateConnected:
default:
FWKLOG( ("IOFireWireSBP2Login<%p> : resume notify, nothing to do\n", this) );
break;
}
}
}
void IOFireWireSBP2Login::terminateNotify( void )
{
FWKLOG( ( "IOFireWireSBP2Login<%p> : terminate notify\n", this ) );
if( fLogoutPending )
{
fLogoutPending = false;
}
else
{
switch( fLoginState )
{
case kLoginStateReconnect:
if( fReconnectTimeoutTimerSet )
fReconnectTimeoutCommand->cancel(kIOReturnAborted);
break;
case kLoginStateLoggingIn:
abortLogin();
break;
case kLoginStateIdle:
case kLoginStateLoggingOut:
case kLoginStateConnected:
case kLoginStateTerminated:
default:
FWKLOG( ("IOFireWireSBP2Login<%p> : terminate notify, nothing to do\n", this) );
break;
}
if( fLoginRetryTimeoutTimerSet )
{
fLoginRetryTimeoutCommand->cancel( kIOReturnAborted );
fLoginState = kLoginStateTerminated;
completeLogin( kIOReturnNotAttached );
}
}
}
void IOFireWireSBP2Login::startReconnectTimer( void )
{
IOReturn status = kIOReturnSuccess;
fLoginState = kLoginStateReconnect;
if( fReconnectTimeoutTimerSet )
fReconnectTimeoutCommand->cancel(kIOReturnAborted);
FWKLOGASSERT( status == kIOReturnSuccess );
fReconnectTimeoutCommand->reinit( ((fManagementTimeout + 1000) * 1000),
IOFireWireSBP2Login::reconnectTimeoutStatic, this);
fReconnectTimeoutTimerSet = true;
status = fReconnectTimeoutCommand->submit();
if( status != kIOReturnSuccess )
{
fReconnectTimeoutTimerSet = false;
}
#if FWLOGGING
if( fReconnectTimeoutTimerSet )
FWKLOG( ("IOFireWireSBP2Login<%p> : reconnect timeout set for %d microseconds \n", this, ((fManagementTimeout + 1000) * 1000)) );
#endif
}
void IOFireWireSBP2Login::doReconnect( void )
{
FWKLOG( ("IOFireWireSBP2Login<%p> : reconnect\n", this) );
IOReturn status = fTarget->beginIOCriticalSection();
if( status != kIOReturnSuccess )
{
IOLog( "IOFireWireSBP2Login<0x%08lx>::doReconnect fTarget->beginIOCriticalSection() returned 0x%08lx\n", (UInt32)status);
return;
}
fInCriticalSection = true;
fCriticalSectionCount++;
fReconnectWriteCommand->reinit( FWAddress(0x0000ffff, 0xf0000000 + (fManagementOffset << 2)),
fReconnectWriteCommandMemory, IOFireWireSBP2Login::reconnectWriteCompleteStatic,
this, true );
fUnit->getNodeIDGeneration(fLoginGeneration, fLoginNodeID, fLocalNodeID);
fReconnectWriteInProgress = true;
if( fLoginFlags & kFWSBP2DontSynchronizeMgmtAgent )
status = fReconnectWriteCommand->submit();
else
status = fTarget->synchMgmtAgentAccess( fReconnectWriteCommand );
if( status == kIOFireWireBusReset )
{
fReconnectWriteInProgress = false;
}
else if( status != kIOReturnSuccess )
{
fLoginState = kLoginStateIdle;
fReconnectWriteInProgress = false;
sendReconnectNotification( kIOMessageFWSBP2ReconnectFailed );
}
}
void IOFireWireSBP2Login::restartReconnect( void )
{
if( fReconnectWriteInProgress )
{
fReconnectWriteInterrupted = true;
}
else
{
doReconnect();
}
}
void IOFireWireSBP2Login::reconnectWriteCompleteStatic( void *refcon, IOReturn status, IOFireWireNub *device,
IOFWCommand *fwCmd )
{
((IOFireWireSBP2Login*)refcon)->reconnectWriteComplete( status, device, fwCmd );
}
void IOFireWireSBP2Login::reconnectWriteComplete( IOReturn status, IOFireWireNub *device, IOFWCommand *fwCmd )
{
FWKLOG( ("IOFireWireSBP2Login<%p> : reconnectWriteComplete \n", this) );
fReconnectWriteInProgress = false;
if( fReconnectWriteInterrupted )
{
fReconnectWriteInterrupted = false;
doReconnect();
}
else if( status == kIOFireWireResponseBase+kFWResponseConflictError )
{
startReconnectRetryTimer();
}
}
void IOFireWireSBP2Login::reconnectTimeoutStatic( void *refcon, IOReturn status, IOFireWireBus *bus,
IOFWBusCommand *fwCmd )
{
((IOFireWireSBP2Login*)refcon)->reconnectTimeout( status, bus, fwCmd );
}
void IOFireWireSBP2Login::reconnectTimeout( IOReturn status, IOFireWireBus *bus, IOFWBusCommand *fwCmd )
{
fReconnectTimeoutTimerSet = false;
FWKLOG( ("IOFireWireSBP2Login<%p> : reconnect timeout proc, status = 0x%08lx\n", this, status) );
if( fInCriticalSection )
{
fInCriticalSection = false;
if( fCriticalSectionCount > 0 )
{
fCriticalSectionCount--;
}
fTarget->endIOCriticalSection();
}
if(status == kIOReturnTimeout)
{
FWKLOG( ("IOFireWireSBP2Login<0x%08lx> : reconnect timeout\n") );
if( fLoginState == kLoginStateReconnect )
{
fLoginState = kLoginStateIdle;
stopReconnectRetryTimer();
if( fLogoutPending )
executeLogout();
else
sendReconnectNotification( kIOMessageFWSBP2ReconnectFailed );
}
}
}
UInt32 IOFireWireSBP2Login::reconnectStatusBlockWriteStatic(void *refcon, UInt16 nodeID, IOFWSpeed &speed,
FWAddress addr, UInt32 len, const void *buf,
IOFWRequestRefCon lockRead)
{
return ((IOFireWireSBP2Login*)refcon)->reconnectStatusBlockWrite( nodeID, speed, addr, len, buf, lockRead );
}
UInt32 IOFireWireSBP2Login::reconnectStatusBlockWrite( UInt16 nodeID, IOFWSpeed &speed, FWAddress addr,
UInt32 len, const void *buf, IOFWRequestRefCon lockRead )
{
FWKLOG( ("IOFireWireSBP2Login<%p> : reconnect status block write\n", this) );
if( !fReconnectTimeoutTimerSet )
{
FWKLOG( ("IOFireWireSBP2Login<%p> : reconnect status block write after timer went off\n", this) );
return kFWResponseComplete;
}
if( fLoginGeneration != fControl->getGeneration() )
{
FWKLOG( ("IOFireWireSBP2Login<%p> : reconnect status block write for wrong generation\n", this) );
return kFWResponseComplete;
}
bzero( &fReconnectStatusBlock, sizeof(fReconnectStatusBlock) );
if( len < sizeof(fReconnectStatusBlock) )
bcopy( buf, &fReconnectStatusBlock, len);
else
bcopy( buf, &fReconnectStatusBlock, sizeof(fReconnectStatusBlock));
if( ( ( ( fReconnectStatusBlock.details >> 4 ) & 3 ) == kFWSBP2RequestComplete ) &&
( fReconnectStatusBlock.sbpStatus == kFWSBP2NoSense ) )
{
FWKLOG( ( "IOFireWireSBP2Login<%p> : successful reconnect\n", this ) );
fReconnectTimeoutCommand->cancel(kIOReturnAborted);
fLastORB = NULL;
fLastORBAddress = FWAddress(0,0);
fLoginState = kLoginStateConnected;
fFetchAgentWriteCommand->reinit( fFetchAgentAddress,
fFetchAgentWriteCommandMemory,
IOFireWireSBP2Login::fetchAgentWriteCompleteStatic, this, true );
fFetchAgentWriteCommand->updateNodeID( fLoginGeneration, fLoginNodeID );
fFetchAgentWriteCommand->setRetries( 0 );
if( fUnsolicitedStatusEnableRequested )
{
fUnsolicitedStatusEnableRequested = false;
executeUnsolicitedStatusEnable();
}
if( fLogoutPending )
{
fLogoutPending = false;
executeLogout();
}
else
sendReconnectNotificationWithStatusBlock( kIOMessageFWSBP2ReconnectComplete );
}
else if( ( ( ( fReconnectStatusBlock.details >> 4 ) & 3 ) == kFWSBP2RequestComplete ) &&
( fReconnectStatusBlock.sbpStatus == kFWSBP2UnspecifiedError ) )
{
startReconnectRetryTimer();
}
else
{
FWKLOG( ( "IOFireWireSBP2Login<%p> : reconnect failed\n", this ) );
fReconnectTimeoutCommand->cancel(kIOReturnAborted);
fLoginState = kLoginStateIdle;
if( fLogoutPending )
{
fLogoutPending = false;
executeLogout();
}
else
sendReconnectNotificationWithStatusBlock( kIOMessageFWSBP2ReconnectFailed );
}
return kFWResponseComplete;
}
void IOFireWireSBP2Login::startReconnectRetryTimer( void )
{
stopReconnectRetryTimer();
fReconnectRetryTimeoutTimerSet = true;
if( fReconnectRetryTimeoutCommand->submit() != kIOReturnSuccess )
fReconnectRetryTimeoutTimerSet = false;
}
void IOFireWireSBP2Login::stopReconnectRetryTimer( void )
{
if( fReconnectRetryTimeoutTimerSet )
fReconnectRetryTimeoutCommand->cancel( kIOReturnAborted );
}
void IOFireWireSBP2Login::reconnectRetryTimeoutStatic( void *refcon, IOReturn status,
IOFireWireBus *bus, IOFWBusCommand *fwCmd)
{
((IOFireWireSBP2Login*)refcon)->reconnectRetryTimeout( status, bus, fwCmd );
}
void IOFireWireSBP2Login::reconnectRetryTimeout( IOReturn status, IOFireWireBus *bus, IOFWBusCommand *fwCmd)
{
fReconnectRetryTimeoutTimerSet = false;
if( status == kIOReturnTimeout )
{
FWKLOG( ("IOFireWireSBP2Login<%p> : reconnect retry timer fired\n", this) );
doReconnect();
}
}
void IOFireWireSBP2Login::sendReconnectNotification( UInt32 event )
{
FWSBP2ReconnectParams params;
if( (fLoginFlags & kFWSBP2DontSynchronizeMgmtAgent) == 0 )
fTarget->completeMgmtAgentAccess( );
params.login = this;
params.generation = fLoginGeneration;
params.reconnectStatusBlock = NULL;
params.reconnectStatusBlockLength = 0;
FWKLOG( ( "IOFireWireSBP2Login<%p> : arg address 0x%08lx\n", this, ¶ms ) );
FWKLOG( ( "IOFireWireSBP2Login<%p> : reconnectStatusBlock 0x%08lx, reconnectStatusBlockLength 0x%08lx\n", this, params.reconnectStatusBlock, params.reconnectStatusBlockLength ) );
fTarget->messageClients( event, ¶ms );
fLUN->messageClients( event, ¶ms );
}
void IOFireWireSBP2Login::sendReconnectNotificationWithStatusBlock( UInt32 event )
{
FWSBP2ReconnectParams params;
if( (fLoginFlags & kFWSBP2DontSynchronizeMgmtAgent) == 0 )
fTarget->completeMgmtAgentAccess( );
params.login = this;
params.generation = fLoginGeneration;
params.reconnectStatusBlock = &fReconnectStatusBlock;
params.reconnectStatusBlockLength = sizeof(FWSBP2StatusBlock);
FWKLOG( ( "IOFireWireSBP2Login<%p> : arg address 0x%08lx\n", this, ¶ms ) );
FWKLOG( ( "IOFireWireSBP2Login<%p> : reconnectStatusBlock 0x%08lx, reconnectStatusBlockLength 0x%08lx\n", this, params.reconnectStatusBlock, params.reconnectStatusBlockLength ) );
fTarget->messageClients( event, ¶ms );
fLUN->messageClients( event, ¶ms );
}
#pragma mark -
IOReturn IOFireWireSBP2Login::submitLogout( void )
{
IOReturn status = kIOReturnSuccess;
status = fGate->runAction( staticExecuteLogout );
return status;
}
IOReturn IOFireWireSBP2Login::staticExecuteLogout( OSObject *self, void *, void *, void *, void * )
{
return ((IOFireWireSBP2Login *)self)->executeLogout();
}
IOReturn IOFireWireSBP2Login::executeLogout( void )
{
FWKLOG( ( "IOFireWireSBP2Login<%p> : executeLogout\n", this ) );
if( fLoginState == kLoginStateLoggingOut || fLogoutPending )
{
return kIOReturnBusy;
}
if( fSuspended )
{
fLogoutPending = true;
}
if( fLoginState == kLoginStateLoggingIn )
{
return kIOReturnBusy;
}
if( fLoginState == kLoginStateReconnect )
{
fLogoutPending = true;
}
if( fLoginState == kLoginStateIdle )
{
return kIOReturnSuccess;
}
if( fLoginState == kLoginStateConnected )
{
fLoginState = kLoginStateLoggingOut;
fLogoutORB.loginID = OSSwapHostToBigInt16(fLoginID);
fLogoutWriteCommand->reinit( FWAddress(0x0000ffff, 0xf0000000 + (fManagementOffset << 2)),
fLogoutWriteCommandMemory, IOFireWireSBP2Login::logoutWriteCompleteStatic,
this, true );
fLogoutWriteCommand->updateNodeID( fLoginGeneration, fLoginNodeID );
IOReturn status = fTarget->beginIOCriticalSection();
if( status == kIOReturnSuccess )
{
fInCriticalSection = true;
fCriticalSectionCount++;
fLogoutWriteInProgress = true;
status = fLogoutWriteCommand->submit();
}
if( status != kIOReturnSuccess )
{
fLogoutWriteInProgress = false;
if( fInCriticalSection )
{
fInCriticalSection = false;
if( fCriticalSectionCount > 0 )
{
fCriticalSectionCount--;
}
fTarget->endIOCriticalSection();
}
return status;
}
}
return kIOReturnSuccess;
}
void IOFireWireSBP2Login::logoutWriteCompleteStatic( void *refcon, IOReturn status, IOFireWireNub *device,
IOFWCommand *fwCmd )
{
((IOFireWireSBP2Login*)refcon)->logoutWriteComplete( status, device, fwCmd );
}
void IOFireWireSBP2Login::logoutWriteComplete( IOReturn status, IOFireWireNub *device, IOFWCommand *fwCmd )
{
FWKLOG( ( "IOFireWireSBP2Login<%p> : logoutWriteComplete \n", this ) );
fLogoutWriteInProgress = false;
if( status == kIOReturnSuccess )
{
fLogoutTimeoutTimerSet = true;
if( fLogoutTimeoutCommand->submit() != kIOReturnSuccess )
fLogoutTimeoutTimerSet = false;
}
else
{
fLoginState = kLoginStateIdle;
completeLogout( status ); }
}
void IOFireWireSBP2Login::logoutTimeoutStatic( void *refcon, IOReturn status, IOFireWireBus *bus, IOFWBusCommand *fwCmd )
{
((IOFireWireSBP2Login*)refcon)->logoutTimeout( status, bus, fwCmd );
}
void IOFireWireSBP2Login::logoutTimeout( IOReturn status, IOFireWireBus *bus, IOFWBusCommand *fwCmd )
{
FWKLOG( ( "IOFireWireSBP2Login<%p> : logoutTimeout \n", this ) );
fLogoutTimeoutTimerSet = false;
if( status != kIOReturnSuccess )
{
FWKLOG( ("IOFireWireSBP2Login<%p> : logout timed out\n", this) );
fLoginState = kLoginStateIdle;
completeLogout( status );
}
}
void IOFireWireSBP2Login::completeLogout( IOReturn state, const void *buf, UInt32 len )
{
FWKLOG( ( "IOFireWireSBP2Login<%p> : completeLogout\n", this ) );
if( fInCriticalSection )
{
fInCriticalSection = false;
if( fCriticalSectionCount > 0 )
{
fCriticalSectionCount--;
}
fTarget->endIOCriticalSection();
}
if( fLogoutCompletionCallback != NULL )
{
FWSBP2LogoutCompleteParams params;
params.login = this;
params.generation = fLoginGeneration;
params.status = state;
params.statusBlock = (FWSBP2StatusBlock*)buf;
params.statusBlockLength = len;
(*fLogoutCompletionCallback)(fLogoutCompletionRefCon, ¶ms);
}
}
void IOFireWireSBP2Login::clearAllTasksInSet( void )
{
stopFetchAgentRetryTimer();
IOFireWireSBP2ORB * item;
fORBSetIterator->reset();
while( (item = (IOFireWireSBP2ORB *) fORBSetIterator->getNextObject()) )
{
if( isORBTimerSet( item ) )
{
cancelORBTimer( item );
if( isORBAppended( item ) )
{
setORBIsAppended( item, false );
if( fCriticalSectionCount > 0 )
{
fCriticalSectionCount--;
}
fTarget->endIOCriticalSection();
}
if( fStatusNotifyCallback != NULL )
{
FWSBP2NotifyParams params;
params.message = 0;
params.length = 0;
params.notificationEvent = kFWSBP2NormalCommandReset;
params.generation = fLoginGeneration;
params.commandObject = item;
(*fStatusNotifyCallback)(fStatusNotifyRefCon, ¶ms );
}
}
}
if( fORBToWrite )
{
item = fORBToWrite;
fORBToWrite = 0;
if( item->getCommandTimeout() != 0 )
{
if( fStatusNotifyCallback != NULL )
{
FWSBP2NotifyParams params;
params.message = 0;
params.length = 0;
params.notificationEvent = kFWSBP2NormalCommandReset;
params.generation = fLoginGeneration;
params.commandObject = item;
(*fStatusNotifyCallback)(fStatusNotifyRefCon, ¶ms );
}
}
}
fLastORB = NULL;
fLastORBAddress = FWAddress(0,0);
}
#pragma mark -
IOFireWireSBP2ORB * IOFireWireSBP2Login::createORB( void )
{
IOFireWireSBP2ORB * orb = new IOFireWireSBP2ORB;
if( orb != NULL && !initORBWithLogin( orb, this ) )
{
orb->release();
orb = NULL;
}
else
{
addORB( orb );
}
return orb;
}
IOReturn IOFireWireSBP2Login::addORB( IOFireWireSBP2ORB * orb )
{
IOReturn status = kIOReturnSuccess;
status = fGate->runAction( staticExecuteAddORB, (void*)orb );
return status;
}
IOReturn IOFireWireSBP2Login::staticExecuteAddORB( OSObject *self, void * orb, void *, void *, void * )
{
return ((IOFireWireSBP2Login *)self)->executeAddORB( (IOFireWireSBP2ORB*)orb );
}
IOReturn IOFireWireSBP2Login::executeAddORB( IOFireWireSBP2ORB * orb )
{
return fORBSet->setObject( orb );
}
IOReturn IOFireWireSBP2Login::removeORB( IOFireWireSBP2ORB * orb )
{
IOReturn status = kIOReturnSuccess;
status = fGate->runAction( staticExecuteRemoveORB, (void*)orb );
return status;
}
IOReturn IOFireWireSBP2Login::staticExecuteRemoveORB( OSObject *self, void * orb, void *, void *, void * )
{
return ((IOFireWireSBP2Login *)self)->executeRemoveORB( (IOFireWireSBP2ORB*)orb );
}
IOReturn IOFireWireSBP2Login::executeRemoveORB( IOFireWireSBP2ORB * orb )
{
fORBSet->removeObject( orb );
return kIOReturnSuccess;
}
IOReturn IOFireWireSBP2Login::submitORB( IOFireWireSBP2ORB * orb )
{
IOReturn status = kIOReturnSuccess;
status = fGate->runAction( staticExecuteORB, (void*)orb );
return status;
}
IOReturn IOFireWireSBP2Login::staticExecuteORB( OSObject *self, void * orb, void *, void *, void * )
{
return ((IOFireWireSBP2Login *)self)->executeORB( ( IOFireWireSBP2ORB *)orb );
}
IOReturn IOFireWireSBP2Login::executeORB( IOFireWireSBP2ORB * orb )
{
IOReturn status = kIOReturnSuccess;
UInt32 commandFlags = 0;
if( !isConnected() )
{
status = kIOFireWireBusReset; }
if( status == kIOReturnSuccess )
{
commandFlags = orb->getCommandFlags();
}
if( status == kIOReturnSuccess )
{
if( (fFetchAgentWriteCommandInUse || fFetchAgentRetryTimerSet) && ( commandFlags & kFWSBP2CommandImmediate ) && fORBToWrite ) {
FWKLOG(("IOFireWireSBP2Login<%p> : fetchAgentWriteCommand still in use\n", this ));
status = kIOReturnNoResources;
}
}
if( status == kIOReturnSuccess )
{
UInt32 generation = orb->getCommandGeneration();
if( commandFlags & kFWSBP2CommandCheckGeneration && !fControl->checkGeneration(generation) )
status = kIOFireWireBusReset;
}
if( status == kIOReturnSuccess )
{
UInt32 targetFlags = fTarget->getTargetFlags();
if( targetFlags & kIOFWSBP2FailsOnBusResetsDuringIO )
{
UInt32 orbFlags = orb->getCommandFlags();
orb->setCommandFlags( orbFlags | kFWSBP2CommandCompleteNotify );
}
}
if( status == kIOReturnSuccess )
{
orb->setFetchAgentWriteRetries( 20 );
orb->setFetchAgentWriteRetryInterval( 1000 );
prepareORBForExecution(orb);
}
if( status == kIOReturnSuccess && fFastStartSupported )
{
UInt32 maxPacketBytes = 1 << fUnit->maxPackLog(true,fFetchAgentAddress);
UInt32 fastStartPacketBytes = fFastStartMaxPayload << 2;
if( fastStartPacketBytes == 0 )
{
fastStartPacketBytes = maxPacketBytes;
}
else if( maxPacketBytes < fastStartPacketBytes )
{
fastStartPacketBytes = maxPacketBytes;
}
IOBufferMemoryDescriptor * descriptor = OSDynamicCast(IOBufferMemoryDescriptor, fFetchAgentWriteCommandMemory);
if( descriptor == NULL )
{
panic( "IOFireWireSBP2Login<0x%08lx>::executeORB() - fFetchAgentWriteCommandMemory is not an IOBufferMemoryDescriptor!\n", this );
}
descriptor->setLength( fastStartPacketBytes );
{
FWAddress orbAddress(0,0);
if( commandFlags & kFWSBP2CommandImmediate )
{
orbAddress = FWAddress(0,0);
}
else
{
orbAddress = fLastORBAddress;
}
if( orbAddress.addressHi == 0 && orbAddress.addressLo == 0 )
{
orbAddress.nodeID = OSSwapHostToBigInt16(0x8000);
}
else
{
orbAddress.nodeID = OSSwapHostToBigInt16(fLocalNodeID);
}
descriptor->writeBytes( 0, &orbAddress, sizeof(FWAddress) );
}
{
FWAddress orbAddress(0,0);
orb->getORBAddress( &orbAddress );
orbAddress.nodeID = OSSwapHostToBigInt16(fLocalNodeID);
orbAddress.addressHi = OSSwapHostToBigInt16(orbAddress.addressHi);
orbAddress.addressLo = OSSwapHostToBigInt32(orbAddress.addressLo);
descriptor->writeBytes( 8, &orbAddress, sizeof(FWAddress) );
}
orb->prepareFastStartPacket( descriptor );
fastStartPacketBytes = descriptor->getLength();
}
#if FWDIAGNOSTICS
((IOFireWireSBP2Diagnostics*)(fLUN->getDiagnostics()))->incrementExecutedORBCount();
#endif
if( status == kIOReturnSuccess )
{
if( commandFlags & kFWSBP2CommandImmediate )
{
FWAddress orbAddress(0,0);
orb->getORBAddress( &orbAddress );
fLastORBAddress.nodeID = OSSwapHostToBigInt16(orbAddress.nodeID);
fLastORBAddress.addressHi = OSSwapHostToBigInt16(orbAddress.addressHi);
fLastORBAddress.addressLo = OSSwapHostToBigInt32(orbAddress.addressLo);
fLastORB = orb;
if( fFetchAgentWriteCommandInUse )
{
fORBToWrite = orb;
}
else
{
startORBTimer(orb);
if( fTarget->beginIOCriticalSection() == kIOReturnSuccess )
{
#if PANIC_ON_DOUBLE_APPEND
if( isORBAppended( orb ) )
{
panic( "IOFireWireSBP2Login::executeORB - double appending orb!\n" );
}
#endif
fCriticalSectionCount++;
setORBIsAppended( orb, true );
status = appendORBImmediate( orb );
}
}
}
else
{
startORBTimer(orb);
if( fTarget->beginIOCriticalSection() == kIOReturnSuccess )
{
#if PANIC_ON_DOUBLE_APPEND
if( isORBAppended( orb ) )
{
panic( "IOFireWireSBP2Login::executeORB - double appending orb!\n" );
}
#endif
fCriticalSectionCount++;
setORBIsAppended( orb, true );
status = appendORB( orb );
if( status != kIOReturnSuccess )
{
cancelORBTimer( orb );
setORBIsAppended( orb, false );
if( fCriticalSectionCount > 0 )
{
fCriticalSectionCount--;
}
fTarget->endIOCriticalSection();
}
}
}
}
return status;
}
bool IOFireWireSBP2Login::isConnected( void )
{
return (fLoginState == kLoginStateConnected);
}
void IOFireWireSBP2Login::setFetchAgentWriteCompletion( void * refCon, FWSBP2FetchAgentWriteCallback completion )
{
fFetchAgentWriteCompletion = completion;
fFetchAgentWriteRefCon = refCon;
}
void IOFireWireSBP2Login::fetchAgentWriteCompleteStatic( void *refcon, IOReturn status, IOFireWireNub *device, IOFWCommand *fwCmd )
{
((IOFireWireSBP2Login*)refcon)->fetchAgentWriteComplete( status, device, fwCmd );
}
void IOFireWireSBP2Login::fetchAgentWriteComplete( IOReturn status, IOFireWireNub *device, IOFWCommand *fwCmd )
{
IOFireWireSBP2ORB * orb = fORBToWrite;
fFetchAgentWriteCommandInUse = false;
if( fLastORB != NULL )
{
UInt32 retries = fLastORB->getFetchAgentWriteRetries();
int ack = fFetchAgentWriteCommand->getAckCode();
int rcode = fFetchAgentWriteCommand->getResponseCode();
if( status != kIOReturnSuccess &&
status != kIOFireWireBusReset &&
retries != 0 )
{
if( (ack == kFWAckBusyX) ||
(ack == kFWAckBusyA) ||
(ack == kFWAckBusyB) )
{
#if PANIC_ON_DOUBLE_APPEND
panic( "IOFireWireSBP2Login::fetchAgentWriteComplete fetch agent write failed!\n" );
#endif
retries--;
fLastORB->setFetchAgentWriteRetries( retries );
if( kFetchAgentRetryInterval > kFetchAgentSplitTimeout )
{
startFetchAgentRetryTimer( kFetchAgentRetryInterval - kFetchAgentSplitTimeout );
}
else
{
appendORBImmediate( fLastORB );
}
return;
}
else if ( (ack == kFWAckDataError) ||
(rcode == kFWResponseConflictError) ||
(rcode == kFWResponseDataError) )
{
#if PANIC_ON_DOUBLE_APPEND
panic( "IOFireWireSBP2Login::fetchAgentWriteComplete fetch agent write failed!\n" );
#endif
retries--;
fLastORB->setFetchAgentWriteRetries( retries );
UInt32 interval = fLastORB->getFetchAgentWriteRetryInterval();
fLastORB->setFetchAgentWriteRetryInterval( interval + 1000 );
startFetchAgentRetryTimer( interval );
return;
}
}
}
fORBToWrite = 0;
if( orb && status != kIOFireWireBusReset )
{
startORBTimer( orb );
if( fTarget->beginIOCriticalSection() == kIOReturnSuccess )
{
#if PANIC_ON_DOUBLE_APPEND
if( isORBAppended( orb ) )
{
panic( "IOFireWireSBP2Login::fetchAgentWriteComplete - double appending orb!\n" );
}
#endif
fCriticalSectionCount++;
setORBIsAppended( orb, true );
appendORBImmediate( orb );
}
}
if( fFetchAgentWriteCompletion != NULL )
(*fFetchAgentWriteCompletion)( fFetchAgentWriteRefCon, status, fLastORB );
}
void IOFireWireSBP2Login::startFetchAgentRetryTimer( UInt32 duration )
{
FWKLOGASSERT( fFetchAgentRetryTimerSet == false );
stopFetchAgentRetryTimer();
fFetchAgentRetryTimerCommand->reinit( duration,
IOFireWireSBP2Login::fetchAgentRetryTimerStatic, this );
fFetchAgentRetryTimerSet = true;
IOReturn status = fFetchAgentRetryTimerCommand->submit();
if( status != kIOReturnSuccess )
{
fFetchAgentRetryTimerSet = false;
}
}
void IOFireWireSBP2Login::stopFetchAgentRetryTimer( void )
{
if( fFetchAgentRetryTimerSet )
{
fFetchAgentRetryTimerCommand->cancel(kIOReturnAborted);
}
}
void IOFireWireSBP2Login::fetchAgentRetryTimerStatic( void *refcon, IOReturn status, IOFireWireBus *bus, IOFWBusCommand *fwCmd )
{
((IOFireWireSBP2Login*)refcon)->fetchAgentRetryTimer( status, bus, fwCmd );
}
void IOFireWireSBP2Login::fetchAgentRetryTimer( IOReturn status, IOFireWireBus *bus, IOFWBusCommand *fwCmd )
{
FWKLOG( ( "IOFireWireSBP2Login<%p>IOFireWireSBP2Login::fetchAgentRetryTimer\n", this ) );
fFetchAgentRetryTimerSet = false;
if( status == kIOReturnTimeout )
{
appendORBImmediate( fLastORB );
}
}
bool IOFireWireSBP2Login::isFetchAgentWriteInProgress( void )
{
return (fFetchAgentWriteCommandInUse || fFetchAgentRetryTimerSet);
}
void IOFireWireSBP2Login::setFetchAgentResetCompletion( void * refCon, FWSBP2StatusCallback completion )
{
fFetchAgentResetCompletion = completion;
fFetchAgentResetRefCon = refCon;
}
IOReturn IOFireWireSBP2Login::submitFetchAgentReset( void )
{
IOReturn status = kIOReturnSuccess;
status = fGate->runAction( staticExecuteFetchAgentReset );
return status;
}
IOReturn IOFireWireSBP2Login::staticExecuteFetchAgentReset( OSObject *self, void *, void *, void *, void * )
{
return ((IOFireWireSBP2Login *)self)->executeFetchAgentReset();
}
IOReturn IOFireWireSBP2Login::executeFetchAgentReset( void )
{
IOReturn status = kIOReturnSuccess;
switch( fLoginState )
{
case kLoginStateConnected:
if( fFetchAgentResetInProgress )
fFetchAgentResetCommand->cancel( kIOReturnAborted );
fFetchAgentResetInProgress = true;
fFetchAgentResetCommand->reinit( fFetchAgentResetAddress,
&fFetchAgentResetBuffer, 1,
IOFireWireSBP2Login::fetchAgentResetCompleteStatic,
this, true );
fFetchAgentResetCommand->updateNodeID( fLoginGeneration, fLoginNodeID );
fFetchAgentResetCommand->submit();
break;
case kLoginStateLoggingIn:
case kLoginStateReconnect:
case kLoginStateIdle:
case kLoginStateLoggingOut:
default:
status = kIOReturnError;
break;
}
return status;
}
void IOFireWireSBP2Login::fetchAgentResetCompleteStatic( void *refcon, IOReturn status, IOFireWireNub *device, IOFWCommand *fwCmd )
{
((IOFireWireSBP2Login*)refcon)->fetchAgentResetComplete( status, device, fwCmd );
}
void IOFireWireSBP2Login::fetchAgentResetComplete( IOReturn status, IOFireWireNub *device, IOFWCommand *fwCmd )
{
FWKLOG( ("IOFireWireSBP2Login<%p> : fetch agent reset complete\n", this) );
fFetchAgentResetInProgress = false;
if( status == kIOReturnSuccess )
{
clearAllTasksInSet();
}
if( status != kIOReturnAborted )
{
if( fFetchAgentResetCompletion )
(*fFetchAgentResetCompletion)( fFetchAgentResetRefCon, status );
}
}
IOReturn IOFireWireSBP2Login::ringDoorbell( void )
{
IOReturn status = kIOReturnSuccess;
status = fGate->runAction( staticExecuteDoorbell );
return status;
}
IOReturn IOFireWireSBP2Login::staticExecuteDoorbell( OSObject *self, void *, void *, void *, void * )
{
return ((IOFireWireSBP2Login *)self)->executeDoorbell();
}
IOReturn IOFireWireSBP2Login::executeDoorbell( void )
{
if( isConnected() )
{
if( fDoorbellInProgress )
{
fDoorbellRingAgain = true;
return kIOReturnSuccess;
}
fDoorbellInProgress = true;
fDoorbellCommand->reinit( fDoorbellAddress,
&fDoorbellBuffer, 1,
IOFireWireSBP2Login::doorbellCompleteStatic,
this, true );
fDoorbellCommand->updateNodeID( fLoginGeneration, fLoginNodeID );
fDoorbellCommand->submit();
}
else
return kIOReturnError;
return kIOReturnSuccess;
}
void IOFireWireSBP2Login::doorbellCompleteStatic( void *refcon, IOReturn status, IOFireWireNub *device, IOFWCommand *fwCmd )
{
((IOFireWireSBP2Login*)refcon)->doorbellComplete( status, device, fwCmd );
}
void IOFireWireSBP2Login::doorbellComplete( IOReturn status, IOFireWireNub *device, IOFWCommand *fwCmd )
{
FWKLOG( ("IOFireWireSBP2Login<%p> : doorbell complete\n", this) );
fDoorbellInProgress = false;
if( fDoorbellRingAgain )
{
fDoorbellRingAgain = false;
executeDoorbell();
}
}
IOReturn IOFireWireSBP2Login::enableUnsolicitedStatus( void )
{
IOReturn status = kIOReturnSuccess;
status = fGate->runAction( staticExecuteUnsolicitedStatusEnable );
return status;
}
IOReturn IOFireWireSBP2Login::staticExecuteUnsolicitedStatusEnable( OSObject *self, void *, void *, void *, void * )
{
return ((IOFireWireSBP2Login *)self)->executeUnsolicitedStatusEnable();
}
IOReturn IOFireWireSBP2Login::executeUnsolicitedStatusEnable( void )
{
IOReturn status = kIOReturnSuccess;
switch( fLoginState )
{
case kLoginStateConnected:
if( fUnsolicitedStatusEnableInProgress )
fUnsolicitedStatusEnableCommand->cancel( kIOReturnAborted );
fUnsolicitedStatusEnableInProgress = true;
fUnsolicitedStatusEnableCommand->reinit( fUnsolicitedStatusEnableAddress,
&fUnsolicitedStatusEnableBuffer, 1,
IOFireWireSBP2Login::unsolicitedStatusEnableCompleteStatic,
this, true );
fUnsolicitedStatusEnableCommand->updateNodeID( fLoginGeneration, fLoginNodeID );
fUnsolicitedStatusEnableCommand->submit();
break;
case kLoginStateLoggingIn:
case kLoginStateReconnect:
fUnsolicitedStatusEnableRequested = true; break;
case kLoginStateIdle:
case kLoginStateLoggingOut:
default:
status = kIOReturnError;
break;
}
return status;
}
void IOFireWireSBP2Login::unsolicitedStatusEnableCompleteStatic( void *refcon, IOReturn status, IOFireWireNub *device, IOFWCommand *fwCmd )
{
((IOFireWireSBP2Login*)refcon)->unsolicitedStatusEnableComplete( status, device, fwCmd );
}
void IOFireWireSBP2Login::unsolicitedStatusEnableComplete( IOReturn status, IOFireWireNub *device, IOFWCommand *fwCmd )
{
FWKLOG( ("IOFireWireSBP2Login<%p> : unsolicitedStatusEnableComplete complete\n", this) );
fUnsolicitedStatusEnableInProgress = false;
if( status == kIOFireWireBusReset )
{
fUnsolicitedStatusEnableRequested = true; }
}
void IOFireWireSBP2Login::setBusyTimeoutRegisterValue( UInt32 timeout )
{
fSetBusyTimeoutBuffer = OSSwapHostToBigInt32(timeout);
executeSetBusyTimeout();
}
IOReturn IOFireWireSBP2Login::executeSetBusyTimeout( void )
{
if( fSetBusyTimeoutInProgress )
fSetBusyTimeoutCommand->cancel( kIOReturnAborted );
fSetBusyTimeoutInProgress = true;
fSetBusyTimeoutCommand->reinit( fSetBusyTimeoutAddress,
&fSetBusyTimeoutBuffer, 1,
IOFireWireSBP2Login::setBusyTimeoutCompleteStatic,
this, true );
fSetBusyTimeoutCommand->submit();
return kIOReturnSuccess;
}
void IOFireWireSBP2Login::setBusyTimeoutCompleteStatic( void *refcon, IOReturn status, IOFireWireNub *device, IOFWCommand *fwCmd )
{
((IOFireWireSBP2Login*)refcon)->setBusyTimeoutComplete( status, device, fwCmd );
}
void IOFireWireSBP2Login::setBusyTimeoutComplete( IOReturn status, IOFireWireNub *device, IOFWCommand *fwCmd )
{
FWKLOG( ("IOFireWireSBP2Login<%p> : setBusyTimeoutComplete\n", this) );
fSetBusyTimeoutInProgress = false;
}
IOReturn IOFireWireSBP2Login::appendORBImmediate( IOFireWireSBP2ORB * orb )
{
if( fFetchAgentWriteCommandInUse )
fFetchAgentWriteCommand->cancel( kIOReturnAborted );
fFetchAgentWriteCommandInUse = true;
fFetchAgentWriteCommand->reinit( fFetchAgentAddress,
fFetchAgentWriteCommandMemory,
IOFireWireSBP2Login::fetchAgentWriteCompleteStatic, this, true );
fFetchAgentWriteCommand->setRetries( 0 );
fFetchAgentWriteCommand->updateNodeID( fLoginGeneration, fLoginNodeID );
return fFetchAgentWriteCommand->submit();
}
IOReturn IOFireWireSBP2Login::appendORB( IOFireWireSBP2ORB * orb )
{
IOReturn status = kIOReturnSuccess;
if( fLastORB != NULL && fLastORB != orb )
{
FWAddress orb_address(0,0);
orb->getORBAddress( &orb_address );
setNextORBAddress( fLastORB, orb_address );
fLastORBAddress.nodeID = OSSwapHostToBigInt16(orb_address.nodeID);
fLastORBAddress.addressHi = OSSwapHostToBigInt16(orb_address.addressHi);
fLastORBAddress.addressLo = OSSwapHostToBigInt32(orb_address.addressLo);
fLastORB = orb;
}
else
status = kIOReturnError;
return status;
}
void IOFireWireSBP2Login::sendTimeoutNotification( IOFireWireSBP2ORB * orb )
{
if( isORBAppended( orb ) )
{
setORBIsAppended( orb, false );
if( fCriticalSectionCount > 0 )
{
fCriticalSectionCount--;
}
fTarget->endIOCriticalSection();
}
if( fStatusNotifyCallback != NULL )
{
FWSBP2NotifyParams params;
params.message = 0;
params.length = 0;
params.notificationEvent = kFWSBP2NormalCommandTimeout;
params.generation = fLoginGeneration;
params.commandObject = orb;
(*fStatusNotifyCallback)(fStatusNotifyRefCon, ¶ms );
}
}
void IOFireWireSBP2Login::setAddressLoForLoginORBAndResponse( UInt32 addressLoORB, UInt32 addressLoResponse )
{
IOFWSBP2PseudoAddressSpace * space;
UInt32 addressLoORBMasked = addressLoORB & 0xfffffff0;
UInt32 addressLoResponseMasked = addressLoResponse & 0xfffffff0;
fControl->closeGate();
FWKLOG(( "IOFireWireSBP2Login::setAddressLoForLoginORBAndResponse<%p> - set ORB addressLo to 0x%08lx, set Response addressLo to 0x%08lx\n", this, addressLoORBMasked, addressLoResponseMasked ));
space = OSDynamicCast( IOFWSBP2PseudoAddressSpace, fLoginORBAddressSpace );
if( space != NULL )
{
fLoginORBAddress.addressLo = OSSwapHostToBigInt32(addressLoORBMasked);
space->setAddressLo( addressLoORBMasked );
}
space = OSDynamicCast( IOFWSBP2PseudoAddressSpace, fLoginResponseAddressSpace );
if( space != NULL )
{
fLoginResponseAddress.addressLo = addressLoResponseMasked;
fLoginORB.loginResponseAddressLo = OSSwapHostToBigInt32(fLoginResponseAddress.addressLo);
space->setAddressLo( addressLoResponseMasked );
}
fControl->openGate();
}
bool IOFireWireSBP2Login::isPhysicalAccessEnabled( void )
{
return fPhysicalAccessEnabled;
}
UInt32 IOFireWireSBP2Login::getARDMMax( void )
{
return fARDMAMax;
}
#pragma mark -
bool IOFireWireSBP2Login::initORBWithLogin( IOFireWireSBP2ORB * orb, IOFireWireSBP2Login * login )
{
return orb->initWithLogin( login );
}
void IOFireWireSBP2Login::setNextORBAddress( IOFireWireSBP2ORB * orb, FWAddress address )
{
orb->setNextORBAddress( address );
}
void IOFireWireSBP2Login::fetchAgentWriteComplete( IOFireWireSBP2ORB * orb, IOReturn status )
{
}
bool IOFireWireSBP2Login::isORBTimerSet( IOFireWireSBP2ORB * orb )
{
return orb->isTimerSet();
}
void IOFireWireSBP2Login::cancelORBTimer( IOFireWireSBP2ORB * orb )
{
orb->cancelTimer();
}
void IOFireWireSBP2Login::startORBTimer( IOFireWireSBP2ORB * orb )
{
orb->startTimer();
}
void IOFireWireSBP2Login::prepareORBForExecution( IOFireWireSBP2ORB * orb )
{
orb->prepareORBForExecution();
}
bool IOFireWireSBP2Login::isORBAppended( IOFireWireSBP2ORB * orb )
{
return orb->isAppended();
}
void IOFireWireSBP2Login::setORBIsAppended( IOFireWireSBP2ORB * orb, bool state )
{
orb->setIsAppended( state );
}
void IOFireWireSBP2Login::removeLogin( void )
{
fLUN->removeLogin( this);
}
IOFireWireSBP2Target * IOFireWireSBP2Login::getTarget( void )
{
return fLUN->getTarget();
}