IOFireWireSBP2Target.cpp [plain text]
#include <IOKit/IOMessage.h>
#define FIREWIREPRIVATE
#include <IOKit/firewire/IOFireWireController.h>
#undef FIREWIREPRIVATE
#include <IOKit/firewire/IOConfigDirectory.h>
#include <IOKit/firewire/IOFireWireDevice.h>
#include <IOKit/IODeviceTreeSupport.h>
#include <IOKit/sbp2/IOFireWireSBP2LUN.h>
#include <IOKit/sbp2/IOFireWireSBP2Target.h>
#include "FWDebugging.h"
const OSSymbol *gCommand_Set_Spec_ID_Symbol = NULL;
const OSSymbol *gCommand_Set_Symbol = NULL;
const OSSymbol *gModule_Vendor_ID_Symbol = NULL;
const OSSymbol *gCommand_Set_Revision_Symbol = NULL;
const OSSymbol *gIOUnit_Symbol = NULL;
const OSSymbol *gFirmware_Revision_Symbol = NULL;
const OSSymbol *gDevice_Type_Symbol = NULL;
const OSSymbol *gGUID_Symbol = NULL;
const OSSymbol *gUnit_Characteristics_Symbol = NULL;
const OSSymbol *gManagement_Agent_Offset_Symbol = NULL;
const OSSymbol *gFast_Start_Symbol = NULL;
OSDefineMetaClassAndStructors(IOFireWireSBP2Target, IOService);
OSMetaClassDefineReservedUnused(IOFireWireSBP2Target, 0);
OSMetaClassDefineReservedUnused(IOFireWireSBP2Target, 1);
OSMetaClassDefineReservedUnused(IOFireWireSBP2Target, 2);
OSMetaClassDefineReservedUnused(IOFireWireSBP2Target, 3);
OSMetaClassDefineReservedUnused(IOFireWireSBP2Target, 4);
OSMetaClassDefineReservedUnused(IOFireWireSBP2Target, 5);
OSMetaClassDefineReservedUnused(IOFireWireSBP2Target, 6);
OSMetaClassDefineReservedUnused(IOFireWireSBP2Target, 7);
OSMetaClassDefineReservedUnused(IOFireWireSBP2Target, 8);
bool IOFireWireSBP2Target::start( IOService *provider )
{
fProviderUnit = OSDynamicCast(IOFireWireUnit, provider);
if (fProviderUnit == NULL)
return false;
fControl = fProviderUnit->getController();
fFlags = kIOFWSBP2FailsOnBusResetsDuringIO;
fOpenFromTarget = false;
fOpenFromLUNCount = 0;
if( gCommand_Set_Spec_ID_Symbol == NULL )
gCommand_Set_Spec_ID_Symbol = OSSymbol::withCString("Command_Set_Spec_ID");
if( gCommand_Set_Symbol == NULL )
gCommand_Set_Symbol = OSSymbol::withCString("Command_Set");
if( gModule_Vendor_ID_Symbol == NULL )
gModule_Vendor_ID_Symbol = OSSymbol::withCString("Vendor_ID");
if( gCommand_Set_Revision_Symbol == NULL )
gCommand_Set_Revision_Symbol = OSSymbol::withCString("Command_Set_Revision");
if( gIOUnit_Symbol == NULL )
gIOUnit_Symbol = OSSymbol::withCString("IOUnit");
if( gFirmware_Revision_Symbol == NULL )
gFirmware_Revision_Symbol = OSSymbol::withCString("Firmware_Revision");
if( gDevice_Type_Symbol == NULL )
gDevice_Type_Symbol = OSSymbol::withCString("Device_Type");
if( gGUID_Symbol == NULL )
gGUID_Symbol = OSSymbol::withCString("GUID");
if( gUnit_Characteristics_Symbol == NULL )
gUnit_Characteristics_Symbol = OSSymbol::withCString("Unit_Characteristics");
if( gManagement_Agent_Offset_Symbol == NULL )
gManagement_Agent_Offset_Symbol = OSSymbol::withCString("Management_Agent_Offset");
if( gFast_Start_Symbol == NULL )
gFast_Start_Symbol = OSSymbol::withCString("Fast_Start");
if (IOService::start(provider))
{
IOFireWireController * controller = fProviderUnit->getController();
IOService * fwim = (IOService*)controller->getLink();
OSObject * prop = NULL;
UInt32 byteCount1, byteCount2;
byteCount1 = 0;
prop = fwim->getProperty( "FWMaxAsyncReceiveBytes" );
if( prop )
{
byteCount1 = ((OSNumber*)prop)->unsigned32BitValue();
if( byteCount1 != 0 )
{
byteCount1 -= 32;
}
}
byteCount2 = 0;
prop = fwim->getProperty( "FWMaxAsyncReceivePackets" );
if( prop )
{
UInt32 packetCount = ((OSNumber*)prop)->unsigned32BitValue();
if( packetCount != 0 )
{
byteCount2 = (packetCount - 1) * 512; }
}
UInt32 size = byteCount1 < byteCount2 ? byteCount1 : byteCount2;
if( size != 0)
setProperty( "SBP2ReceiveBufferByteCount", size, 32 );
scanForLUNs();
}
else
return false;
FWKLOG( ( "IOFireWireSBP2Target : started\n" ) );
return true;
}
void IOFireWireSBP2Target::stop( IOService *provider )
{
FWKLOG( ( "IOFireWireSBP2Target : stopped\n" ) );
IOService::stop(provider);
}
IOReturn IOFireWireSBP2Target::message( UInt32 type, IOService *nub, void *arg )
{
IOReturn res = kIOReturnUnsupported;
FWKLOG( ("IOFireWireSBP2Target : message 0x%x, arg 0x%08lx\n", type, arg) );
res = IOService::message(type, nub, arg);
if( kIOReturnUnsupported == res )
{
switch (type)
{
case kIOMessageServiceIsTerminated:
FWKLOG( ( "IOFireWireSBP2Target : kIOMessageServiceIsTerminated\n" ) );
res = kIOReturnSuccess;
break;
case kIOMessageServiceIsSuspended:
FWKLOG( ( "IOFireWireSBP2Target : kIOMessageServiceIsSuspended\n" ) );
res = kIOReturnSuccess;
break;
case kIOMessageServiceIsResumed:
FWKLOG( ( "IOFireWireSBP2Target : kIOMessageServiceIsResumed\n" ) );
configurePhysicalFilter();
res = kIOReturnSuccess;
break;
default: break;
}
}
if( type != kIOMessageServiceIsTerminated )
messageClients( type, arg );
return res;
}
IOFireWireUnit * IOFireWireSBP2Target::getFireWireUnit( void )
{
return fProviderUnit;
}
bool IOFireWireSBP2Target::handleOpen( IOService * forClient, IOOptionBits options, void * arg )
{
bool ok = true;
FWKLOG(( "enter handleOpen fOpenFromLUNCount = %d, fOpenFromTarget = %d\n", fOpenFromLUNCount, fOpenFromTarget ));
IOFireWireSBP2LUN * lunClient = OSDynamicCast( IOFireWireSBP2LUN, forClient );
if( lunClient != NULL )
{
if( fOpenFromTarget )
return false;
if( fOpenFromLUNCount == 0 )
{
ok = fProviderUnit->open(this, options, arg);
if( ok )
{
fOpenFromLUNCount++;
ok = IOService::handleOpen( this, options, arg );
FWKLOG(( "called open\n" ));
}
}
else
{
fOpenFromLUNCount++;
}
}
else
{
if( fOpenFromLUNCount != 0 )
return false;
if( !fOpenFromTarget ) {
ok = fProviderUnit->open(this, options, arg);
if( ok )
{
fOpenFromTarget = true;
ok = IOService::handleOpen( forClient, options, arg );
FWKLOG(( "called open\n" ));
}
}
else
ok = false; }
FWKLOG(( "exit handleOpen fOpenFromLUNCount = %d, fOpenFromTarget = %d\n", fOpenFromLUNCount, fOpenFromTarget ));
return ok;
}
void IOFireWireSBP2Target::handleClose( IOService * forClient, IOOptionBits options )
{
FWKLOG(( "enter handleClose fOpenFromLUNCount = %d, fOpenFromTarget = %d\n", fOpenFromLUNCount, fOpenFromTarget ));
IOFireWireSBP2LUN * lunClient = OSDynamicCast( IOFireWireSBP2LUN, forClient );
if( lunClient != NULL )
{
if( fOpenFromLUNCount != 0 ) {
fOpenFromLUNCount--;
if( fOpenFromLUNCount == 0 ) {
IOService::handleClose( this, options);
fProviderUnit->close(this, options);
FWKLOG(( "called close\n" ));
}
}
}
else
{
if( fOpenFromTarget ) {
fOpenFromTarget = false;
IOService::handleClose(forClient, options);
fProviderUnit->close(this, options);
FWKLOG(( "called close\n" ));
}
}
FWKLOG(( "exit handleClose fOpenFromLUNCount = %d, fOpenFromTarget = %d\n", fOpenFromLUNCount, fOpenFromTarget ));
}
bool IOFireWireSBP2Target::handleIsOpen( const IOService * forClient ) const
{
if( fOpenFromLUNCount != 0 )
{
IOFireWireSBP2LUN * lunClient = OSDynamicCast( IOFireWireSBP2LUN, forClient );
return (lunClient != NULL );
}
if( fOpenFromTarget )
{
return IOService::handleIsOpen( forClient );
}
return false;
}
void IOFireWireSBP2Target::scanForLUNs( void )
{
IOReturn status = kIOReturnSuccess;
IOReturn tempStatus = kIOReturnSuccess;
UInt32 cmdSpecID = 0;
UInt32 cmdSet = 0;
UInt32 vendorID = 0;
UInt32 softwareRev = 0;
UInt32 firmwareRev = 0;
UInt32 lun = 0;
UInt32 devType = 0;
UInt32 unitCharacteristics = 0;
UInt32 offset = 0;
UInt32 revision = 0;
bool fastStartSupported = false;
UInt32 fastStart = 0;
IOConfigDirectory * directory;
IOFireWireDevice * device;
IOService * providerService = fProviderUnit->getProvider();
if( providerService == NULL )
status = kIOReturnError;
if( status == kIOReturnSuccess )
{
device = OSDynamicCast( IOFireWireDevice, providerService );
if( device == NULL )
status = kIOReturnError;
FWKLOG( ("IOFireWireSBP2Target : unit = 0x%08lx, provider = 0x%08lx, device = 0x%08lx\n", fProviderUnit, providerService, device) );
}
if( status == kIOReturnSuccess )
{
status = device->getConfigDirectory( directory );
FWKLOG( ( "IOFireWireSBP2Target : status = %d\n", status ) );
}
if( status == kIOReturnSuccess )
tempStatus = directory->getKeyValue( kConfigModuleVendorIdKey, vendorID );
status = fProviderUnit->getConfigDirectory( directory );
FWKLOG( ( "IOFireWireSBP2Target : status = %d\n", status ) );
if( status == kIOReturnSuccess )
status = directory->getKeyValue( kCmdSpecIDKey, cmdSpecID );
if( status == kIOReturnSuccess )
status = directory->getKeyValue( kCmdSetKey, cmdSet );
if( status == kIOReturnSuccess )
status = directory->getKeyValue( kUnitCharacteristicsKey, unitCharacteristics );
status = directory->getKeyValue( kManagementAgentOffsetKey, offset );
if( status == kIOReturnSuccess )
{
IOService *parent = this;
while(parent) {
if(parent->inPlane(gIODTPlane))
break;
parent = parent->getProvider();
}
if(parent) {
char location[9];
sprintf(location, "%lx", offset);
attachToParent(parent, gIODTPlane);
setLocation(location, gIODTPlane);
setName("sbp-2", gIODTPlane);
}
}
if( status == kIOReturnSuccess )
tempStatus = directory->getKeyValue( kRevisionKey, revision );
if( status == kIOReturnSuccess && revision != 0 )
{
tempStatus = directory->getKeyValue( kFastStartKey, fastStart );
if( tempStatus == kIOReturnSuccess )
{
fastStartSupported = true;
}
}
if( status == kIOReturnSuccess )
tempStatus = directory->getKeyValue( kSoftwareRevKey, softwareRev );
if( status == kIOReturnSuccess )
tempStatus = directory->getKeyValue( kFirmwareRevKey, firmwareRev );
FWKLOG( ( "IOFireWireSBP2Target : status = %d, cmdSpecID = %d, cmdSet = %d, vendorID = %d, softwareRev = %d, firmwareRev = %d\n",
status, cmdSpecID, cmdSet, vendorID, softwareRev, firmwareRev ) );
if( status == kIOReturnSuccess )
{
for( int pos = 0; pos < directory->getNumEntries(); pos++ )
{
UInt32 key;
tempStatus = directory->getIndexEntry( pos, key );
FWKLOG( ( "IOFireWireSBP2Target : tempStatus = %d, pos = %d, key = %d\n",
tempStatus, pos, key ) );
if( tempStatus == kIOReturnSuccess && key >> kConfigEntryKeyValuePhase == kLUNKey )
{
UInt32 data;
tempStatus = directory->getIndexValue( pos, data );
if( tempStatus == kIOReturnSuccess )
{
lun = data & 0x0000ffff;
devType = (data & 0x001f0000) >> 16;
FWKLOG( ( "IOFireWireSBP2Target : cmdSpecID = %d, cmdSet = %d, vendorID = %d, softwareRev = %d\n",
cmdSpecID, cmdSet, vendorID, softwareRev ) );
FWKLOG( ( "IOFireWireSBP2Target : firmwareRev = %d, lun = %d, devType = %d\n",
firmwareRev, lun, devType ) );
FWKLOG( ( "IOFireWireSBP2Target : unitCharacteristics = %d, managementOffset = %d,\n",
unitCharacteristics, offset ) );
FWKLOG( ( "IOFireWireSBP2Target : revision = %d, fastStartSupported = %d, fastStart = 0x%08lx\n",
revision, fastStartSupported, fastStart ) );
if( (cmdSpecID & 0x00ffffff) || (cmdSet & 0x00ffffff) )
{
createLUN( cmdSpecID, cmdSet, vendorID, softwareRev, firmwareRev, lun, devType, unitCharacteristics, offset, fastStartSupported, fastStart );
}
}
}
}
}
if( status == kIOReturnSuccess )
{
OSIterator * directoryIterator;
IOConfigDirectory * lunDirectory;
UInt32 lunValue;
status = directory->getKeySubdirectories( kLUNDirectoryKey, directoryIterator );
while( (lunDirectory = OSDynamicCast(IOConfigDirectory,directoryIterator->getNextObject())) != NULL )
{
if( revision != 0 )
{
tempStatus = directory->getKeyValue( kFastStartKey, fastStart );
if( tempStatus == kIOReturnSuccess )
{
fastStartSupported = true;
}
}
tempStatus = lunDirectory->getKeyValue( kLUNKey, lunValue );
if( tempStatus == kIOReturnSuccess )
{
lun = lunValue & 0x0000ffff;
devType = (lunValue & 0x001f0000) >> 16;
FWKLOG( ( "IOFireWireSBP2Target : cmdSpecID = %d, cmdSet = %d, vendorID = %d, softwareRev = %d\n",
cmdSpecID, cmdSet, vendorID, softwareRev ) );
FWKLOG( ( "IOFireWireSBP2Target : firmwareRev = %d, lun = %d, devType = %d\n",
firmwareRev, lun, devType ) );
FWKLOG( ( "IOFireWireSBP2Target : revision = %d, fastStartSupported = %d, fastStart = 0x%08lx\n",
revision, fastStartSupported, fastStart ) );
if( (cmdSpecID & 0x00ffffff) || (cmdSet & 0x00ffffff) )
{
createLUN( cmdSpecID, cmdSet, vendorID, softwareRev, firmwareRev, lun, devType, unitCharacteristics, offset, fastStartSupported, fastStart );
}
}
}
directoryIterator->release();
}
OSObject *prop;
if( status == kIOReturnSuccess )
{
prop = OSNumber::withNumber( cmdSpecID, 32 );
setProperty( gCommand_Set_Spec_ID_Symbol, prop );
prop->release();
prop = OSNumber::withNumber( cmdSet, 32 );
setProperty( gCommand_Set_Symbol, prop );
prop->release();
prop = OSNumber::withNumber( vendorID, 32 );
setProperty( gModule_Vendor_ID_Symbol, prop );
prop->release();
prop = OSNumber::withNumber( softwareRev, 32 );
setProperty( gCommand_Set_Revision_Symbol, prop );
prop->release();
prop = OSNumber::withNumber( firmwareRev, 32 );
setProperty( gFirmware_Revision_Symbol, prop );
prop->release();
prop = OSNumber::withNumber( devType, 32 );
setProperty( gDevice_Type_Symbol, prop );
prop->release();
prop = fProviderUnit->getProperty(gGUID_Symbol);
if( prop )
setProperty( gGUID_Symbol, prop );
registerService();
}
}
IOReturn IOFireWireSBP2Target::createLUN( UInt32 cmdSpecID, UInt32 cmdSet, UInt32 vendorID, UInt32 softwareRev,
UInt32 firmwareRev, UInt32 lun, UInt32 devType, UInt32 unitCharacteristics,
UInt32 managementOffset, bool fastStartSupported, UInt32 fastStart )
{
IOReturn status = kIOReturnSuccess;
OSDictionary * propTable = OSDictionary::withCapacity(7);
OSObject *prop;
if( propTable )
{
#if 0
const OSSymbol * propSymbol;
OSDictionary * userClient = OSDictionary::withCapacity(2);
propSymbol = OSSymbol::withCString("A45B8156-B51B-11D4-AB4B-000A277E7234");
prop = OSString::withCString("IOFireWireSBP2Lib.plugin");
userClient->setObject( propSymbol, prop );
prop->release();
propSymbol->release();
propSymbol = OSSymbol::withCString("631F68D2-B9E6-11D4-8147-000A277E7234");
prop = OSString::withCString("SBP2SampleDriver.plugin");
userClient->setObject( propSymbol, prop );
prop->release();
propSymbol->release();
propSymbol = OSSymbol::withCString("IOCFPlugInTypes");
propTable->setObject( propSymbol, userClient );
propSymbol->release();
#endif
prop = OSNumber::withNumber( cmdSpecID, 32 );
propTable->setObject( gCommand_Set_Spec_ID_Symbol, prop );
prop->release();
prop = OSNumber::withNumber( cmdSet, 32 );
propTable->setObject( gCommand_Set_Symbol, prop );
prop->release();
prop = OSNumber::withNumber( vendorID, 32 );
propTable->setObject( gModule_Vendor_ID_Symbol, prop );
prop->release();
prop = OSNumber::withNumber( softwareRev, 32 );
propTable->setObject( gCommand_Set_Revision_Symbol, prop );
prop->release();
prop = OSNumber::withNumber( firmwareRev, 32 );
propTable->setObject( gFirmware_Revision_Symbol, prop );
prop->release();
prop = OSNumber::withNumber( lun, 32 );
propTable->setObject( gIOUnit_Symbol, prop );
prop->release();
prop = OSNumber::withNumber( devType, 32 );
propTable->setObject( gDevice_Type_Symbol, prop );
prop->release();
prop = OSNumber::withNumber( unitCharacteristics, 32 );
propTable->setObject( gUnit_Characteristics_Symbol, prop );
prop->release();
prop = OSNumber::withNumber( managementOffset, 32 );
propTable->setObject( gManagement_Agent_Offset_Symbol, prop );
prop->release();
if( fastStartSupported )
{
prop = OSNumber::withNumber( fastStart, 32 );
propTable->setObject( gFast_Start_Symbol, prop );
prop->release();
}
prop = fProviderUnit->getProperty(gGUID_Symbol);
if( prop )
propTable->setObject( gGUID_Symbol, prop );
IOFireWireSBP2LUN * newLUN = new IOFireWireSBP2LUN;
if( newLUN != NULL )
{
bool success = true;
if( success )
success = newLUN->init(propTable);
if( success )
success = newLUN->attach(this);
if( success )
newLUN->registerService();
FWKLOG( ( "IOFireWireSBP2Target : created LUN object - success = %d\n", success ) );
if( !success )
status = kIOReturnError;
newLUN->release();
}
propTable->release();
}
return status;
}
bool IOFireWireSBP2Target::matchPropertyTable(OSDictionary * table)
{
if( !IOService::matchPropertyTable(table) )
return false;
bool res = compareProperty(table, gCommand_Set_Spec_ID_Symbol) &&
compareProperty(table, gCommand_Set_Symbol) &&
compareProperty(table, gModule_Vendor_ID_Symbol) &&
compareProperty(table, gCommand_Set_Revision_Symbol) &&
compareProperty(table, gFirmware_Revision_Symbol) &&
compareProperty(table, gDevice_Type_Symbol) &&
compareProperty(table, gGUID_Symbol);
return res;
}
void IOFireWireSBP2Target::setTargetFlags( UInt32 flags )
{
fFlags |= flags;
FWKLOG(( "IOFireWireSBP2Target::setTargetFlags 0x%08lx\n", fFlags ));
configurePhysicalFilter();
}
void IOFireWireSBP2Target::clearTargetFlags( UInt32 flags )
{
fFlags &= ~flags;
FWKLOG(( "IOFireWireSBP2Target::clearTargetFlags 0x%08lx\n", fFlags ));
configurePhysicalFilter();
}
UInt32 IOFireWireSBP2Target::getTargetFlags( void )
{
return fFlags;
}
void IOFireWireSBP2Target::configurePhysicalFilter( void )
{
bool disablePhysicalAccess = false;
if( fFlags & kIOFWSBP2FailsOnAckBusy )
{
IOFireWireController * controller = fProviderUnit->getController();
IOService * fwim = (IOService*)controller->getLink();
UInt32 deviceCount = 0;
OSData * data = (OSData*)controller->getProperty( "FireWire Self IDs" );
UInt32 numIDs = data->getLength() / sizeof(UInt32);
UInt32 *IDs = (UInt32*)data->getBytesNoCopy();
UInt32 i;
for( i = 0; i < numIDs; i++ )
{
UInt32 current_id = IDs[i];
if( (current_id & kFWSelfIDPacketType) == 0 &&
(current_id & kFWSelfID0L) )
{
deviceCount++;
}
}
if( (deviceCount > 2) && (fwim->getProperty( "PhysicalUnitBlocksOnReads" ) != NULL) )
{
disablePhysicalAccess = true;
}
}
if( disablePhysicalAccess )
{
FWKLOG(( "IOFireWireSBP2Target::configurePhysicalFilter disabling physical access for unit 0x%08lx\n", fProviderUnit ));
fProviderUnit->setNodeFlags( kIOFWDisableAllPhysicalAccess );
}
else
{
FWKLOG(( "IOFireWireSBP2Target::configurePhysicalFilter enabling physical access for unit 0x%08lx\n", fProviderUnit ));
fProviderUnit->clearNodeFlags( kIOFWDisableAllPhysicalAccess );
}
}
IOReturn IOFireWireSBP2Target::beginIOCriticalSection( void )
{
IOReturn status = kIOReturnSuccess;
FWKLOG(( "IOFireWireSBP2Target::beginIOCriticalSection\n" ));
if( fFlags & kIOFWSBP2FailsOnBusResetsDuringIO )
{
FWKLOG(( "IOFireWireSBP2Target::beginIOCriticalSection fControl->disableSoftwareBusResets()\n" ));
status = fControl->disableSoftwareBusResets();
}
FWKLOG(( "IOFireWireSBP2Target::beginIOCriticalSection status = 0x%08lx\n", (UInt32)status ));
return status;
}
void IOFireWireSBP2Target::endIOCriticalSection( void )
{
FWKLOG(( "IOFireWireSBP2Target::endIOCriticalSection\n" ));
if( fFlags & kIOFWSBP2FailsOnBusResetsDuringIO )
{
FWKLOG(( "IOFireWireSBP2Target::endIOCriticalSection fControl->enableSoftwareBusResets()\n" ));
fControl->enableSoftwareBusResets();
}
}