IOFireWireSBP2ManagementORB.cpp [plain text]
#include <IOKit/sbp2/IOFireWireSBP2ManagementORB.h>
#include <IOKit/sbp2/IOFireWireSBP2LUN.h>
#define FIREWIREPRIVATE
#include <IOKit/firewire/IOFireWireController.h>
#undef FIREWIREPRIVATE
#include <IOKit/firewire/IOConfigDirectory.h>
#include "FWDebugging.h"
extern const OSSymbol *gUnit_Characteristics_Symbol;
extern const OSSymbol *gManagement_Agent_Offset_Symbol;
OSDefineMetaClassAndStructors( IOFireWireSBP2ManagementORB, IOFWCommand );
OSMetaClassDefineReservedUnused(IOFireWireSBP2ManagementORB, 1);
OSMetaClassDefineReservedUnused(IOFireWireSBP2ManagementORB, 2);
OSMetaClassDefineReservedUnused(IOFireWireSBP2ManagementORB, 3);
OSMetaClassDefineReservedUnused(IOFireWireSBP2ManagementORB, 4);
OSMetaClassDefineReservedUnused(IOFireWireSBP2ManagementORB, 5);
OSMetaClassDefineReservedUnused(IOFireWireSBP2ManagementORB, 6);
OSMetaClassDefineReservedUnused(IOFireWireSBP2ManagementORB, 7);
OSMetaClassDefineReservedUnused(IOFireWireSBP2ManagementORB, 8);
bool IOFireWireSBP2ManagementORB::initWithLUN( IOFireWireSBP2LUN * lun, void * refCon, FWSBP2ManagementCallback completion )
{
bool res = true;
IOReturn status = kIOReturnSuccess;
ExpansionData * exp_data = (ExpansionData*) IOMalloc( sizeof(ExpansionData) );
if( !exp_data )
{
return false;
}
bzero( exp_data, sizeof(ExpansionData) );
fExpansionData = exp_data;
fLUN = lun;
fUnit = fLUN->getFireWireUnit();
fExpansionData->fInCriticalSection = false;
fControl = fUnit->getController();
fTimeout = 0;
fSync = false;
fCompletionCallback = completion;
fCompletionRefCon = refCon;
fTimeoutTimerSet = false;
fStatusBlockAddressSpace = NULL;
fManagementORBAddressSpace = NULL;
fWriteCommand = NULL;
fWriteCommandMemory = NULL;
fFunction = 0;
fResponseBuf = NULL;
fResponseLen = 0;
fResponseAddressSpace = NULL;
fResponseAddress = NULL;
fCompleting = false;
res = IOFWCommand::initWithController( fControl );
if( res )
{
status = getUnitInformation();
res = ( status == kIOReturnSuccess );
}
if( res )
{
status = allocateResources();
res = ( status == kIOReturnSuccess );
}
return res;
}
IOReturn IOFireWireSBP2ManagementORB::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( ("IOFireWireSBP2ManagementORB<%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; }
return status;
}
IOReturn IOFireWireSBP2ManagementORB::allocateResources( void )
{
IOReturn status = kIOReturnSuccess;
FWAddress host_address(0,0);
if( status == kIOReturnSuccess )
{
fManagementORBAddressSpace = IOFWPseudoAddressSpace::simpleRead( fControl, &host_address,
sizeof(FWSBP2TaskManagementORB), & fManagementORB );
if ( fManagementORBAddressSpace == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
fManagementORBAddress.nodeID = OSSwapHostToBigInt16(host_address.nodeID);
fManagementORBAddress.addressHi = OSSwapHostToBigInt16(host_address.addressHi);
fManagementORBAddress.addressLo = OSSwapHostToBigInt32(host_address.addressLo);
status = fManagementORBAddressSpace->activate();
}
if( status == kIOReturnSuccess )
{
fStatusBlockAddressSpace = fUnit->createPseudoAddressSpace( &fStatusBlockAddress, sizeof(FWSBP2StatusBlock),
NULL, IOFireWireSBP2ManagementORB::statusBlockWriteStatic,
this );
if ( fStatusBlockAddressSpace == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
status = fStatusBlockAddressSpace->activate();
}
if( status == kIOReturnSuccess )
{
fWriteCommandMemory = IOMemoryDescriptor::withAddress( &fManagementORBAddress, 8, kIODirectionOut );
if( fWriteCommandMemory == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
fWriteCommand = fUnit->createWriteCommand( FWAddress(0x0000ffff, 0xf0000000 + (fManagementOffset << 2)),
fWriteCommandMemory,
IOFireWireSBP2ManagementORB::writeCompleteStatic, this, true );
if( fWriteCommand == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
fManagementORB.statusFIFOAddressHi = OSSwapHostToBigInt32((fStatusBlockAddress.nodeID << 16) | fStatusBlockAddress.addressHi);
fManagementORB.statusFIFOAddressLo = OSSwapHostToBigInt32(fStatusBlockAddress.addressLo);
}
if( status == kIOReturnSuccess )
{
fTimeoutCommand = fControl->createDelayedCmd( fManagementTimeout * 1000,
IOFireWireSBP2ManagementORB::handleTimeoutStatic, this );
if( !fTimeoutCommand )
status = kIOReturnNoMemory;
}
return status;
}
void IOFireWireSBP2ManagementORB::free( void )
{
IOReturn status = kIOReturnSuccess;
removeManagementORB( this );
if( fTimeoutTimerSet )
fTimeoutCommand->cancel(kIOReturnAborted);
if( fTimeoutCommand )
fTimeoutCommand->release();
if( fManagementORBAddressSpace != NULL && status == kIOReturnSuccess )
{
fManagementORBAddressSpace->deactivate();
fManagementORBAddressSpace->release();
}
if( fStatusBlockAddressSpace != NULL && status == kIOReturnSuccess )
{
fStatusBlockAddressSpace->deactivate();
fStatusBlockAddressSpace->release();
}
if( fResponseMap != NULL )
{
fResponseMap->release();
fResponseMap = NULL;
}
if( fResponseAddressSpace != NULL && status == kIOReturnSuccess )
{
fResponseAddressSpace->deactivate();
fResponseAddressSpace->release();
}
if( fWriteCommand != NULL )
fWriteCommand->release();
if( fWriteCommandMemory != NULL )
fWriteCommandMemory->release();
if( fExpansionData )
{
IOFree( fExpansionData, sizeof(ExpansionData) );
fExpansionData = NULL;
}
IOFWCommand::free();
}
void IOFireWireSBP2ManagementORB::release() const
{
if( getRetainCount() >= 2 )
IOFWCommand::release(2);
}
IOReturn IOFireWireSBP2ManagementORB::setCommandFunction( UInt32 function )
{
if( function == 0 || function == 3 || function == 4 || function == 7 )
{
return kIOReturnBadArgument;
}
else
{
fFunction = function;
fManagementORB.options &= OSSwapHostToBigInt16(0xfff0);
fManagementORB.options |= OSSwapHostToBigInt16(function | 0x8000); }
return kIOReturnSuccess;
}
UInt32 IOFireWireSBP2ManagementORB::getCommandFunction( void )
{
return fFunction;
}
void IOFireWireSBP2ManagementORB::setManageeCommand( OSObject * command )
{
fManageeCommand = command;
}
OSObject* IOFireWireSBP2ManagementORB::getManageeCommand( void )
{
return fManageeCommand;
}
IOReturn IOFireWireSBP2ManagementORB::setResponseBuffer( void * buf, UInt32 len )
{
IOReturn status = kIOReturnSuccess;
if( fResponseAddressSpace != NULL )
{
fResponseAddressSpace->deactivate();
fResponseAddressSpace->release();
}
fResponseBuf = buf;
fResponseLen = len;
if( status == kIOReturnSuccess && buf != NULL && len != 0 )
{
fResponseAddressSpace = IOFWPseudoAddressSpace::simpleRW( fControl,
&fResponseAddress,
len, buf );
if ( fResponseAddressSpace == NULL )
status = kIOReturnNoMemory;
if( status == kIOReturnSuccess )
{
status = fResponseAddressSpace->activate();
}
}
if( status != kIOReturnSuccess )
{
fResponseBuf = NULL;
fResponseLen = 0;
}
return status;
}
void IOFireWireSBP2ManagementORB::getResponseBuffer( void ** buf, UInt32 * len )
{
*buf = fResponseBuf;
*len = fResponseLen;
}
IOReturn IOFireWireSBP2ManagementORB::setResponseBuffer
( IOMemoryDescriptor * desc )
{
IOReturn status = kIOReturnSuccess;
void * buf = NULL;
UInt32 len = 0;
if( fResponseAddressSpace != NULL )
{
fResponseAddressSpace->deactivate();
fResponseAddressSpace->release();
}
if( fResponseMap != NULL )
{
fResponseMap->release();
}
if( desc != NULL )
{
len = desc->getLength();
fResponseMap = desc->map();
if( fResponseMap != NULL )
{
buf = (void*)fResponseMap->getVirtualAddress();
}
}
fResponseBuf = buf;
fResponseLen = len;
if( status == kIOReturnSuccess && desc != NULL && buf != NULL && len != 0 )
{
fResponseAddressSpace = IOFWPseudoAddressSpace::simpleRW( fControl,
&fResponseAddress,
desc );
if ( fResponseAddressSpace == NULL )
status = kIOReturnNoMemory;
if( status == kIOReturnSuccess )
{
status = fResponseAddressSpace->activate();
}
}
if( status != kIOReturnSuccess )
{
fResponseBuf = NULL;
fResponseLen = 0;
}
return status;
}
IOReturn IOFireWireSBP2ManagementORB::execute( void )
{
FWKLOG( ( "IOFireWireSBP2ManagementORB<%p> : execute\n", this ) );
IOReturn status = kIOReturnSuccess;
IOFireWireSBP2Login * login = NULL;
IOFireWireSBP2ORB * orb = NULL;
switch( fFunction )
{
case kFWSBP2TargetReset:
case kFWSBP2LogicalUnitReset:
case kFWSBP2AbortTaskSet:
login = OSDynamicCast( IOFireWireSBP2Login, fManageeCommand );
if( login == NULL )
status = kIOReturnBadArgument;
break;
case kFWSBP2AbortTask:
orb = OSDynamicCast( IOFireWireSBP2ORB, fManageeCommand );
if( orb == NULL )
status = kIOReturnBadArgument;
else
login = orb->getLogin();
break;
case kFWSBP2QueryLogins:
break;
default:
status = kIOReturnBadArgument;
}
if( status == kIOReturnSuccess && fFunction != kFWSBP2QueryLogins )
{
fManagementORB.loginID = OSSwapHostToBigInt16(login->getLoginID());
}
if( status == kIOReturnSuccess && fFunction == kFWSBP2AbortTask )
{
FWAddress address;
orb->getORBAddress( &address );
fManagementORB.orbOffsetHi = OSSwapHostToBigInt32(0x0000ffff & address.addressHi);
fManagementORB.orbOffsetLo = OSSwapHostToBigInt32(0xfffffffc & address.addressLo);
setORBToDummy( orb );
}
if( status == kIOReturnSuccess && fFunction == kFWSBP2QueryLogins )
{
FWSBP2QueryLoginsORB * queryLoginsORB = (FWSBP2QueryLoginsORB *)&fManagementORB;
queryLoginsORB->lun = OSSwapHostToBigInt16(fLUN->getLUNumber());
queryLoginsORB->queryResponseAddressHi = OSSwapHostToBigInt32(0x0000ffff & fResponseAddress.addressHi);
queryLoginsORB->queryResponseAddressLo = OSSwapHostToBigInt32(fResponseAddress.addressLo);
queryLoginsORB->queryResponseLength = OSSwapHostToBigInt16(fResponseLen);
}
if( status == kIOReturnSuccess )
{
fWriteCommand->reinit( FWAddress(0x0000ffff, 0xf0000000 + (fManagementOffset << 2)),
fWriteCommandMemory,
IOFireWireSBP2ManagementORB::writeCompleteStatic, this, true );
status = fLUN->getTarget()->beginIOCriticalSection();
}
if( status == kIOReturnSuccess )
{
fExpansionData->fInCriticalSection = true;
status = fWriteCommand->submit();
}
if( status != kIOReturnSuccess )
{
if( fExpansionData->fInCriticalSection )
{
fExpansionData->fInCriticalSection = false;
fLUN->getTarget()->endIOCriticalSection();
}
return status;
}
return kIOReturnBusy; }
void IOFireWireSBP2ManagementORB::writeCompleteStatic( void *refcon, IOReturn status, IOFireWireNub *device, IOFWCommand *fwCmd )
{
((IOFireWireSBP2ManagementORB*)refcon)->writeComplete( status, device, fwCmd );
}
void IOFireWireSBP2ManagementORB::writeComplete( IOReturn status, IOFireWireNub *device, IOFWCommand *fwCmd )
{
FWKLOG( ( "IOFireWireSBP2ManagementORB<%p> : write complete\n", this ) );
if( status == kIOReturnSuccess )
{
fTimeoutTimerSet = true;
if( fTimeoutCommand->submit() != kIOReturnSuccess )
fTimeoutTimerSet = false;
}
else
complete( status );
}
void IOFireWireSBP2ManagementORB::handleTimeoutStatic( void *refcon, IOReturn status, IOFireWireBus *bus, IOFWBusCommand *fwCmd )
{
((IOFireWireSBP2ManagementORB*)refcon)->handleTimeout( status, bus, fwCmd );
}
void IOFireWireSBP2ManagementORB::handleTimeout( IOReturn status, IOFireWireBus *bus, IOFWBusCommand *fwCmd )
{
fTimeoutTimerSet = false;
if( status == kIOReturnTimeout )
{
FWKLOG( ( "IOFireWireSBP2ManagementORB<%p> : handle timeout\n", this ) );
complete( kIOReturnTimeout );
}
}
UInt32 IOFireWireSBP2ManagementORB::statusBlockWriteStatic( void *refcon, UInt16 nodeID, IOFWSpeed &speed, FWAddress addr,
UInt32 len, const void *buf, IOFWRequestRefCon lockRead )
{
return ((IOFireWireSBP2ManagementORB*)refcon)->statusBlockWrite( nodeID, addr, len, buf, lockRead );
}
UInt32 IOFireWireSBP2ManagementORB::statusBlockWrite( UInt16 nodeID, FWAddress addr, UInt32 len, const void *buf,
IOFWRequestRefCon lockRead )
{
if( !fTimeoutTimerSet )
return kFWResponseComplete;
fTimeoutCommand->cancel(kIOReturnAborted);
if( fFunction == kFWSBP2AbortTaskSet ||
fFunction == kFWSBP2TargetReset ||
fFunction == kFWSBP2LogicalUnitReset )
{
fCompleting = true;
clearAllTasksInSet();
fCompleting = false;
}
complete( kIOReturnSuccess );
return kFWResponseComplete;
}
void IOFireWireSBP2ManagementORB::suspendedNotify( void )
{
FWKLOG( ( "IOFireWireSBP2ManagementORB<%p> : suspendedNotify\n", this ) );
if( fStatus == kIOReturnBusy && !fCompleting )
{
if( fTimeoutTimerSet )
{
fTimeoutCommand->cancel( kIOReturnAborted );
}
complete( kIOFireWireBusReset );
}
}
IOReturn IOFireWireSBP2ManagementORB::complete( IOReturn state )
{
state = IOFWCommand::complete( state );
FWKLOG( ( "IOFireWireSBP2ManagementORB<%p> : complete\n", this ) );
if( fExpansionData->fInCriticalSection )
{
fExpansionData->fInCriticalSection = false;
fLUN->getTarget()->endIOCriticalSection();
}
if( fCompletionCallback != NULL )
(*fCompletionCallback)(fCompletionRefCon, state, this);
return state;
}
void IOFireWireSBP2ManagementORB::setAsyncCallbackReference( void * asyncRef )
{
bcopy( asyncRef, fCallbackAsyncRef, sizeof(OSAsyncReference64) );
}
void IOFireWireSBP2ManagementORB::getAsyncCallbackReference( void * asyncRef )
{
bcopy( fCallbackAsyncRef, asyncRef, sizeof(OSAsyncReference64) );
}
void IOFireWireSBP2ManagementORB::clearAllTasksInSet( void )
{
fLUN->clearAllTasksInSet();
}
void IOFireWireSBP2ManagementORB::removeManagementORB( IOFireWireSBP2ManagementORB * orb )
{
fLUN->removeManagementORB( orb );
}
void IOFireWireSBP2ManagementORB::setORBToDummy( IOFireWireSBP2ORB * orb )
{
orb->setToDummy();
}