IOFireWireSBP2ORB.cpp [plain text]
#include <IOKit/sbp2/IOFireWireSBP2ORB.h>
#include <IOKit/sbp2/IOFireWireSBP2Login.h>
#include <IOKit/sbp2/IOFireWireSBP2LUN.h>
#include "FWDebugging.h"
#define FIREWIREPRIVATE
#include <IOKit/firewire/IOFireWireController.h>
#undef FIREWIREPRIVATE
#include <IOKit/firewire/IOFWSimpleContiguousPhysicalAddressSpace.h>
OSDefineMetaClassAndStructors( IOFireWireSBP2ORB, IOCommand );
OSMetaClassDefineReservedUnused(IOFireWireSBP2ORB, 0);
OSMetaClassDefineReservedUnused(IOFireWireSBP2ORB, 1);
OSMetaClassDefineReservedUnused(IOFireWireSBP2ORB, 2);
OSMetaClassDefineReservedUnused(IOFireWireSBP2ORB, 3);
OSMetaClassDefineReservedUnused(IOFireWireSBP2ORB, 4);
OSMetaClassDefineReservedUnused(IOFireWireSBP2ORB, 5);
OSMetaClassDefineReservedUnused(IOFireWireSBP2ORB, 6);
OSMetaClassDefineReservedUnused(IOFireWireSBP2ORB, 7);
OSMetaClassDefineReservedUnused(IOFireWireSBP2ORB, 8);
enum
{
kFWSBP2CommandMaxPacketSizeOverride = (1 << 12)
};
bool IOFireWireSBP2ORB::initWithLogin( IOFireWireSBP2Login * login )
{
bool res = true;
fLogin = login;
fLUN = getFireWireLUN();
fUnit = getFireWireUnit();
fControl = fUnit->getController();
fTimeoutTimerSet = false;
fRefCon = NULL;
fBufferAddressSpaceAllocated = false;
fBufferDescriptor = NULL;
fMaxPayloadSize = 0;
fCommandFlags = 0;
fTimeoutDuration = 0;
fDMACommand = NULL;
fConstraintOptions = 0;
if( !IOCommand::init() )
return false;
IOReturn status = allocateResources();
if( status != kIOReturnSuccess )
res = false;
return res;
}
IOReturn IOFireWireSBP2ORB::allocateResources( void )
{
IOReturn status = kIOReturnSuccess;
status = setBufferConstraints( kFWSBP2MaxPageClusterSize, 1, 0 );
if( status == kIOReturnSuccess )
{
UInt32 orbSize = sizeof(FWSBP2ORB) - 4 + fLogin->getMaxCommandBlockSize();
status = allocateORB( orbSize );
}
if( status == kIOReturnSuccess )
{
status = allocatePageTable( PAGE_SIZE / sizeof(FWSBP2PTE) ); }
if( status == kIOReturnSuccess )
{
status = allocateTimer();
}
if( status != kIOReturnSuccess )
{
deallocateTimer();
deallocateORB();
deallocatePageTable();
}
return status;
}
void IOFireWireSBP2ORB::release() const
{
if( getRetainCount() >= 2 )
IOCommand::release(2);
}
void IOFireWireSBP2ORB::free( void )
{
FWKLOG(( "IOFireWireSBP2ORB<%p> : free\n", this ));
removeORB( this );
deallocateTimer();
deallocatePageTable();
deallocateBufferAddressSpace();
deallocateORB();
IOCommand::free();
}
IOReturn IOFireWireSBP2ORB::allocateORB( UInt32 orbSize )
{
IOReturn status = kIOReturnSuccess;
IOFWSimpleContiguousPhysicalAddressSpace * physical_space;
if( status == kIOReturnSuccess )
{
physical_space = fUnit->createSimpleContiguousPhysicalAddressSpace( orbSize, kIODirectionOut );
if( physical_space == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
fORBPhysicalAddressSpace = (IOFWAddressSpace*)physical_space;
fORBDescriptor = physical_space->getMemoryDescriptor();
fORBPhysicalAddress = physical_space->getFWAddress();
fORBBuffer = (FWSBP2ORB *)physical_space->getVirtualAddress();
}
if( status == kIOReturnSuccess )
{
status = fORBPhysicalAddressSpace->activate();
}
if( status == kIOReturnSuccess )
{
fORBPseudoAddressSpace = IOFWPseudoAddressSpace::simpleRW( fControl, &fORBPseudoAddress, fORBDescriptor );
if ( fORBPseudoAddressSpace == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
status = fORBPseudoAddressSpace->activate();
FWKLOG( ( "IOFireWireSBP2ORB<%p> : created orb at phys: 0x%04lx.%08lx psuedo: 0x%04lx.%08lx of size %d\n",
this, fORBPhysicalAddress.addressHi, fORBPhysicalAddress.addressLo, fORBPseudoAddress.addressHi, fORBPseudoAddress.addressLo, orbSize ) );
}
if( status != kIOReturnSuccess )
{
deallocateORB();
}
return status;
}
void IOFireWireSBP2ORB::deallocateORB( void )
{
IOReturn status = kIOReturnSuccess;
if( fORBPhysicalAddressSpace != NULL && status == kIOReturnSuccess )
{
fORBPhysicalAddressSpace->deactivate();
fORBPhysicalAddressSpace->release();
fORBPhysicalAddressSpace = NULL;
}
if( fORBPseudoAddressSpace != NULL && status == kIOReturnSuccess )
{
fORBPseudoAddressSpace->deactivate();
fORBPseudoAddressSpace->release();
fORBPseudoAddressSpace = NULL;
}
}
UInt32 IOFireWireSBP2ORB::calculateTransferSizeLog( bool * clipping )
{
UInt32 transferSizeBytes;
*clipping = false;
transferSizeBytes = 4096;
bool size_override = (fCommandFlags & kFWSBP2CommandMaxPacketSizeOverride);
if( !size_override )
{
UInt32 ARDMAMax = fLogin->getARDMMax();
if( (fCommandFlags & kFWSBP2CommandTransferDataFromTarget) && (ARDMAMax != 0) ) {
transferSizeBytes = ARDMAMax;
*clipping = true;
}
}
UInt32 loginMaxPayloadSize = fLogin->getMaxPayloadSize();
if( loginMaxPayloadSize != 0 && loginMaxPayloadSize < transferSizeBytes )
transferSizeBytes = loginMaxPayloadSize;
if( fMaxPayloadSize != 0 && fMaxPayloadSize < transferSizeBytes )
transferSizeBytes = fMaxPayloadSize;
UInt32 transferSizeLog = 0;
while( (transferSizeBytes >= 8) && (transferSizeLog < 15) )
{
transferSizeBytes >>= 1;
transferSizeLog++;
}
if( !size_override )
{
UInt32 maxPackLog = fUnit->maxPackLog(!(fCommandFlags & kFWSBP2CommandTransferDataFromTarget));
maxPackLog -= 2; if( maxPackLog < transferSizeLog )
{
*clipping = true;
transferSizeLog = maxPackLog;
}
}
else
{
UInt32 maxPackLog = 7;
IOFWSpeed speed = fUnit->FWSpeed();
switch( speed )
{
case kFWSpeed800MBit:
maxPackLog = 10;
break;
case kFWSpeed400MBit:
maxPackLog = 9;
break;
case kFWSpeed200MBit:
maxPackLog = 8;
break;
default:
break;
}
if( maxPackLog < transferSizeLog )
transferSizeLog = maxPackLog;
}
return transferSizeLog;
}
void IOFireWireSBP2ORB::prepareORBForExecution( void )
{
fORBBuffer->nextORBAddressHi = OSSwapHostToBigInt32(0x80000000);
fORBBuffer->nextORBAddressLo = OSSwapHostToBigInt32(0x00000000);
UInt32 generation; UInt16 unitNode;
UInt16 localNode;
fUnit->getNodeIDGeneration( generation, unitNode, localNode );
fORBBuffer->dataDescriptorHi &= OSSwapHostToBigInt32(0x0000ffff);
fORBBuffer->dataDescriptorHi |= OSSwapHostToBigInt32(((UInt32)localNode) << 16);
fORBBuffer->options &= OSSwapHostToBigInt16(0x000f);
if( fCommandFlags & kFWSBP2CommandCompleteNotify )
fORBBuffer->options |= OSSwapHostToBigInt16(0x8000);
if( fCommandFlags & kFWSBP2CommandReservedORB )
fORBBuffer->options |= OSSwapHostToBigInt16(0x2000);
if( fCommandFlags & kFWSBP2CommandVendorORB )
fORBBuffer->options |= OSSwapHostToBigInt16(0x4000);
if( fCommandFlags & kFWSBP2CommandDummyORB )
fORBBuffer->options |= OSSwapHostToBigInt16(0x6000);
if( fCommandFlags & kFWSBP2CommandTransferDataFromTarget )
fORBBuffer->options |= OSSwapHostToBigInt16(0x0800);
IOFWSpeed speed = fUnit->FWSpeed();
switch( speed )
{
case kFWSpeed800MBit:
fORBBuffer->options |= OSSwapHostToBigInt16(0x0300);
break;
case kFWSpeed400MBit:
fORBBuffer->options |= OSSwapHostToBigInt16(0x0200);
break;
case kFWSpeed200MBit:
fORBBuffer->options |= OSSwapHostToBigInt16(0x0100);
break;
default:
break;
}
UInt32 transferSizeLog;
bool clipping;
transferSizeLog = calculateTransferSizeLog( &clipping );
fORBBuffer->options |= OSSwapHostToBigInt16(transferSizeLog << 4);
}
void IOFireWireSBP2ORB::prepareFastStartPacket( IOBufferMemoryDescriptor * descriptor )
{
UInt32 offset = 16;
UInt32 length = descriptor->getLength();
UInt32 orbLength = fORBDescriptor->getLength();
if( length < (offset + orbLength) )
{
IOLog( "IOFireWireSBP2ORB<0x%08lx>::prepareFastStartPacket - fast start packet length (%d) < orblength (%d) + 16\n", this, length, orbLength );
}
descriptor->writeBytes( offset, fORBBuffer, orbLength );
offset += orbLength;
FWSBP2PTE pte;
UInt32 pageTableOffset = 0;
UInt32 pageTableSize = fPTECount * sizeof(FWSBP2PTE);
while( offset < length && pageTableOffset < pageTableSize )
{
if( (length - offset) < sizeof(FWSBP2PTE) )
{
IOLog( "IOFireWireSBP2ORB<0x%08lx>::prepareFastStartPacket - fast start packet not full, yet pte doesn't fit\n", this );
break;
}
fPageTableDescriptor->readBytes( pageTableOffset, &pte, sizeof(FWSBP2PTE) );
descriptor->writeBytes( offset, &pte, sizeof(FWSBP2PTE) );
offset += sizeof(FWSBP2PTE);
pageTableOffset += sizeof(FWSBP2PTE);
}
if( offset > length )
{
IOLog( "IOFireWireSBP2ORB<0x%08lx>::prepareFastStartPacket - offset > length\n", this );
}
descriptor->setLength( offset );
}
#if 0
IOReturn checkMemoryInRange( IOMemoryDescriptor * memory, UInt64 mask, IODMACommand * dma_command_arg )
{
IOReturn status = kIOReturnSuccess;
if( memory == NULL )
{
status = kIOReturnBadArgument;
}
bool memory_prepared = false;
if( dma_command_arg == NULL )
{
if( status == kIOReturnSuccess )
{
status = memory->prepare( kIODirectionInOut );
}
if( status == kIOReturnSuccess )
{
memory_prepared = true;
}
}
UInt64 length = 0;
if( status == kIOReturnSuccess )
{
length = memory->getLength();
}
IODMACommand * dma_command = dma_command_arg;
bool dma_command_prepared = false;
if( dma_command == NULL )
{
if( status == kIOReturnSuccess )
{
dma_command = IODMACommand::withSpecification(
kIODMACommandOutputHost64, 64, 0, (IODMACommand::MappingOptions)(IODMACommand::kMapped | IODMACommand::kIterateOnly), 0, 0, NULL, NULL ); if( dma_command == NULL )
status = kIOReturnError;
}
if( status == kIOReturnSuccess )
{
status = dma_command->setMemoryDescriptor( memory, false );
}
if( status == kIOReturnSuccess )
{
status = dma_command->prepare( 0, length, true );
}
if( status == kIOReturnSuccess )
{
dma_command_prepared = true;
}
}
else
{
#if 0
dma_command->setMemoryDescriptor( memory, false );
dma_command->prepare( 0, length, true );
dma_command_prepared = true;
#endif
}
if( status == kIOReturnSuccess )
{
IOLog( "checkSegments - length = %d\n", length );
UInt64 offset = 0;
while( (offset < length) && (status == kIOReturnSuccess) )
{
IODMACommand::Segment64 segments[10];
UInt32 num_segments = 10;
status = dma_command->gen64IOVMSegments( &offset, segments, &num_segments );
if( status == kIOReturnSuccess )
{
for( UInt32 i = 0; i < num_segments; i++ )
{
IOLog( "checkSegments - offset = 0x%016llx segments[%d].fIOVMAddr = 0x%016llx, fLength = %d\n", offset, i, segments[i].fIOVMAddr, segments[i].fLength );
if( (segments[i].fIOVMAddr & (~mask)) )
{
IOLog( "checkSegmentsFailed - 0x%016llx & 0x%016llx\n", segments[i].fIOVMAddr, mask );
status = kIOReturnNotPermitted;
}
}
}
else
{
IOLog( "checkSegments - offset = %lld 0x%08lx\n", offset, status );
}
}
}
if( dma_command_prepared )
{
dma_command->complete();
dma_command_prepared = false;
}
if( dma_command && (dma_command_arg == NULL) )
{
dma_command->release();
dma_command = NULL;
}
if( memory_prepared )
{
memory->complete();
memory_prepared = false;
}
return status;
}
#endif
IOReturn IOFireWireSBP2ORB::allocateTimer( void )
{
IOReturn status = kIOReturnSuccess;
if( status == kIOReturnSuccess )
{
fTimeoutCommand = (IOFWDelayCommand*)fControl->createDelayedCmd( fTimeoutDuration * 1000,
IOFireWireSBP2ORB::orbTimeoutStatic,
this );
if( fTimeoutCommand == NULL )
status = kIOReturnError;
}
if( status != kIOReturnSuccess )
{
deallocateTimer();
}
return status;
}
void IOFireWireSBP2ORB::deallocateTimer( void )
{
if( fTimeoutTimerSet )
cancelTimer();
if( fTimeoutCommand )
{
fTimeoutCommand->release();
fTimeoutCommand = NULL;
}
}
void IOFireWireSBP2ORB::startTimer( void )
{
if( fCommandFlags & kFWSBP2CommandCompleteNotify )
{
fInProgress = true;
if( fTimeoutDuration != 0 )
{
IOReturn ORBtimeoutSubmitStatus;
FWKLOG( ( "IOFireWireSBP2ORB<%p> : set timeout\n", this ) );
fTimeoutTimerSet = true;
ORBtimeoutSubmitStatus = fTimeoutCommand->submit();
FWPANICASSERT( ORBtimeoutSubmitStatus == kIOReturnSuccess );
}
}
}
bool IOFireWireSBP2ORB::isTimerSet( void )
{
return fInProgress;
}
void IOFireWireSBP2ORB::cancelTimer( void )
{
FWKLOG( ( "IOFireWireSBP2ORB<%p> : cancel timer\n", this ) );
if( fTimeoutTimerSet )
{
fTimeoutCommand->cancel( kIOReturnAborted );
}
else
{
fInProgress = false;
}
}
void IOFireWireSBP2ORB::orbTimeoutStatic( void *refcon, IOReturn status, IOFireWireBus *bus, IOFWBusCommand *fwCmd )
{
((IOFireWireSBP2ORB*)refcon)->orbTimeout( status, bus, fwCmd );
}
void IOFireWireSBP2ORB::orbTimeout( IOReturn status, IOFireWireBus *bus, IOFWBusCommand *fwCmd )
{
fTimeoutTimerSet = false;
fInProgress = false;
if( status == kIOReturnTimeout )
{
FWKLOG( ( "IOFireWireSBP2ORB<%p> : orb timeout\n", this ) );
sendTimeoutNotification( this );
}
else
{
FWKLOG( ( "IOFireWireSBP2ORB<%p> : orb timeout cancelled\n", this ) );
}
}
IOReturn IOFireWireSBP2ORB::allocatePageTable( UInt32 entryCount )
{
IOReturn status = kIOReturnSuccess;
deallocatePageTable();
fPageTableSize = sizeof(FWSBP2PTE) * entryCount;
UInt64 phys_mask = fControl->getFireWirePhysicalAddressMask();
fPageTableDescriptor = IOBufferMemoryDescriptor::inTaskWithPhysicalMask( kernel_task, kIODirectionOutIn, fPageTableSize, phys_mask );
if( fPageTableDescriptor == NULL )
status = kIOReturnNoMemory;
if( status == kIOReturnSuccess )
{
fPageTableDescriptor->setLength( fPageTableSize );
}
bool dma_command_prepared = false;
IODMACommand * dma_command = NULL;
if( status == kIOReturnSuccess )
{
dma_command = IODMACommand::withSpecification(
kIODMACommandOutputHost64, 48, fPageTableSize, (IODMACommand::MappingOptions)(IODMACommand::kMapped | IODMACommand::kIterateOnly), fPageTableSize, 0, NULL, NULL ); if( dma_command == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
status = dma_command->setMemoryDescriptor( fPageTableDescriptor, false );
}
if( status == kIOReturnSuccess )
{
status = dma_command->prepare( 0, fPageTableSize, true );
}
if( status == kIOReturnSuccess )
{
dma_command_prepared = true;
}
IODMACommand::Segment64 segment;
UInt32 numSegments = 1;
if( status == kIOReturnSuccess )
{
UInt64 offset = 0;
status = dma_command->gen64IOVMSegments( &offset, &segment, &numSegments );
}
if( status == kIOReturnSuccess )
{
if( numSegments != 1 )
{
status = kIOReturnNoMemory;
}
}
if( status == kIOReturnSuccess )
{
fPageTablePhysicalLength = segment.fLength;
fPageTablePhysicalAddress.nodeID = 0x0000; fPageTablePhysicalAddress.addressHi = (segment.fIOVMAddr >> 32) & 0x000000000000ffffULL;
fPageTablePhysicalAddress.addressLo = segment.fIOVMAddr & 0x00000000ffffffffULL;
}
if( dma_command_prepared )
{
dma_command->complete();
dma_command_prepared = false;
}
if( dma_command )
{
dma_command->release();
dma_command = NULL;
}
if( status == kIOReturnSuccess )
{
fPageTablePhysicalAddressSpace = fUnit->createPhysicalAddressSpace( fPageTableDescriptor );
if ( fPageTablePhysicalAddressSpace == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
status = fPageTablePhysicalAddressSpace->activate();
}
if( status == kIOReturnSuccess )
{
fPageTablePseudoAddressSpace = IOFWPseudoAddressSpace::simpleRW( fControl, &fPageTablePseudoAddress, fPageTableDescriptor );
if ( fPageTablePseudoAddressSpace == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
status = fPageTablePseudoAddressSpace->activate();
}
if( status != kIOReturnSuccess )
{
deallocatePageTable();
}
return status;
}
void IOFireWireSBP2ORB::deallocatePageTable( void )
{
IOReturn status = kIOReturnSuccess;
if( fPageTablePhysicalAddressSpace != NULL && status == kIOReturnSuccess )
{
fPageTablePhysicalAddressSpace->deactivate();
fPageTablePhysicalAddressSpace->release();
fPageTablePhysicalAddressSpace = NULL;
}
if( fPageTablePseudoAddressSpace != NULL && status == kIOReturnSuccess )
{
fPageTablePseudoAddressSpace->deactivate();
fPageTablePseudoAddressSpace->release();
fPageTablePseudoAddressSpace = NULL;
}
if( fPageTableDescriptor != NULL )
{
fPageTableDescriptor->release();
fPageTableDescriptor = NULL;
}
fPageTableSize = 0;
}
IOReturn IOFireWireSBP2ORB::setBufferConstraints( UInt64 maxSegmentSize, UInt32 alignment, UInt32 options )
{
IOReturn status = kIOReturnSuccess;
if( fBufferAddressSpaceAllocated )
{
status = kIOReturnBusy;
}
if( status == kIOReturnSuccess )
{
fConstraintOptions = options;
deallocateBufferAddressSpace();
if( status == kIOReturnSuccess )
{
UInt32 address_bits = fControl->getFireWirePhysicalAddressBits();
#if 0
#endif
UInt64 segment_size = maxSegmentSize;
if( (segment_size > kFWSBP2MaxPageClusterSize) || (segment_size == 0) )
segment_size = kFWSBP2MaxPageClusterSize;
fDMACommand = IODMACommand::withSpecification(
kIODMACommandOutputHost64, address_bits, segment_size, IODMACommand::kMapped, 0, alignment, NULL, NULL ); if( fDMACommand == NULL )
status = kIOReturnError;
}
}
if( status == kIOReturnSuccess )
{
fBufferAddressSpace = fUnit->createPhysicalAddressSpace( NULL );
if( fBufferAddressSpace == NULL )
{
status = kIOReturnNoMemory;
}
}
if( status == kIOReturnSuccess )
{
((IOFWPhysicalAddressSpace*)fBufferAddressSpace)->setDMACommand( fDMACommand );
}
return status;
}
IOReturn IOFireWireSBP2ORB::prepareBufferAddressSpace( IOMemoryDescriptor * memoryDescriptor )
{
if( fBufferAddressSpaceAllocated )
{
completeBufferAddressSpace();
}
fBufferDescriptor = memoryDescriptor;
fBufferDescriptor->retain();
((IOFWPhysicalAddressSpace*)fBufferAddressSpace)->setMemoryDescriptor( fBufferDescriptor );
fBufferAddressSpace->activate();
if( fConstraintOptions & kFWSBP2ConstraintForceDoubleBuffer )
{
((IOFWPhysicalAddressSpace*)fBufferAddressSpace)->synchronize( IODMACommand::kForceDoubleBuffer | kIODirectionOut );
}
fBufferAddressSpaceAllocated = true;
return kIOReturnSuccess;
}
IOReturn IOFireWireSBP2ORB::completeBufferAddressSpace( void )
{
if( fBufferAddressSpace )
{
fBufferAddressSpace->deactivate();
((IOFWPhysicalAddressSpace*)fBufferAddressSpace)->setMemoryDescriptor( NULL );
}
if( fBufferDescriptor )
{
fBufferDescriptor->release();
fBufferDescriptor = NULL;
}
fBufferAddressSpaceAllocated = false;
if( fORBBuffer )
{
fORBBuffer->dataDescriptorHi = 0;
fORBBuffer->dataDescriptorLo = 0;
fORBBuffer->options &= OSSwapHostToBigInt16(0xfff0); fORBBuffer->dataSize = 0;
}
return kIOReturnSuccess;
}
void IOFireWireSBP2ORB::deallocateBufferAddressSpace( void )
{
fControl->closeGate();
fPTECount = 0;
if( fBufferAddressSpaceAllocated )
{
completeBufferAddressSpace();
}
if( fBufferAddressSpace )
{
fBufferAddressSpace->release();
fBufferAddressSpace = NULL;
}
if( fDMACommand )
{
fDMACommand->release();
fDMACommand = NULL;
}
if( fORBBuffer )
{
fORBBuffer->dataDescriptorHi = 0;
fORBBuffer->dataDescriptorLo = 0;
fORBBuffer->options &= OSSwapHostToBigInt16(0xfff0);
fORBBuffer->dataSize = 0;
}
fPTECount = 0;
fControl->openGate();
}
IOReturn IOFireWireSBP2ORB::setCommandBuffersAsRanges( IOVirtualRange * ranges,
UInt32 withCount,
IODirection withDirection,
task_t withTask,
UInt32 offset,
UInt32 length )
{
IOReturn status = kIOReturnSuccess;
IOMemoryDescriptor * memory = NULL;
if( withCount == 0 )
{
status = kIOReturnBadArgument;
}
IOAddressRange * address_ranges = NULL;
if( status == kIOReturnSuccess )
{
IOAddressRange * address_ranges = IONew( IOAddressRange, withCount );
if( address_ranges == NULL )
{
status = kIOReturnNoMemory;
}
}
if( status == kIOReturnSuccess )
{
for( uint32_t i = 0; i < withCount; i++ )
{
address_ranges[i].address = ranges[i].address;
address_ranges[i].length = ranges[i].length;
}
memory = IOMemoryDescriptor::withAddressRanges( address_ranges, withCount, withDirection, withTask );
if( !memory )
status = kIOReturnNoMemory;
}
if( address_ranges )
{
IODelete( address_ranges, IOAddressRange, withCount );
address_ranges = NULL;
}
if( status == kIOReturnSuccess )
{
status = memory->prepare( withDirection );
}
if( status == kIOReturnSuccess )
{
status = setCommandBuffers( memory, offset, length );
}
if( memory )
{
memory->release();
}
return status;
}
IOReturn IOFireWireSBP2ORB::setCommandBuffersAsRanges64( IOAddressRange * ranges,
uint64_t withCount,
IODirection withDirection,
task_t withTask,
uint64_t offset,
uint64_t length )
{
IOReturn status = kIOReturnSuccess;
IOMemoryDescriptor * memory = NULL;
if( status == kIOReturnSuccess )
{
memory = IOMemoryDescriptor::withAddressRanges( ranges, withCount, withDirection, withTask );
if( !memory )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
status = memory->prepare( withDirection );
}
if( status == kIOReturnSuccess )
{
status = setCommandBuffers( memory, offset, length );
}
if( memory )
{
memory->release();
}
return status;
}
IOReturn IOFireWireSBP2ORB::releaseCommandBuffers( void )
{
return setCommandBuffers( NULL );
}
IOReturn IOFireWireSBP2ORB::setCommandBuffers( IOMemoryDescriptor * memoryDescriptor, UInt32 offset, UInt32 length )
{
IOReturn status = kIOReturnSuccess;
fControl->closeGate();
completeBufferAddressSpace();
if( memoryDescriptor == NULL )
{
fControl->openGate();
return kIOReturnSuccess;
}
#if 0
IOReturn check_status = checkMemoryInRange( memoryDescriptor, 0x000000001fffffff, NULL );
#endif
if( status == kIOReturnSuccess )
{
status = prepareBufferAddressSpace( memoryDescriptor );
}
#if 0
if( check_status != kIOReturnSuccess )
{
IOLog( "After prepare\n" );
check_status = checkMemoryInRange( memoryDescriptor, 0x000000001fffffff, fDMACommand );
IOLog( "After prepare = 0x%08lx\n", check_status );
}
#endif
if( status == kIOReturnSuccess )
{
if( length == 0 )
{
length = fDMACommand->getMemoryDescriptor()->getLength();
}
#if FWLOGGING
UInt32 tempLength = fDMACommand->getMemoryDescriptor()->getLength();
if(length != tempLength)
{
FWKLOG( ( "IOFireWireSBP2ORB<%p> : ### buffer length = %d, memDescriptor length = %d ###\n", this, length, tempLength ) );
}
#endif
}
UInt32 pte = 0;
UInt32 maxPageClipSize = kFWSBP2MaxPageClusterSize;
UInt32 maxPackLog;
bool clipping;
UInt32 targetFlags = fLogin->fTarget->getTargetFlags();
maxPackLog = calculateTransferSizeLog( &clipping );
if( !(targetFlags & kIOFWSBP2DontUsePTPacketLimit) && clipping )
{
switch( maxPackLog )
{
case 10:
maxPageClipSize = 4096;
break;
case 9:
maxPageClipSize = 2048;
break;
case 8:
maxPageClipSize = 1024;
break;
default:
maxPageClipSize = 512;
break;
}
}
if( status == kIOReturnSuccess )
{
UInt32 ptes_allocated = 0;
bool done = false;
while( !done )
{
ptes_allocated = fPageTableSize / sizeof(FWSBP2PTE);
vm_size_t pos = offset;
pte = 0;
while( pos < (length + offset) )
{
UInt64 phys = 0;
UInt64 lengthOfSegment = 0;
IODMACommand::Segment64 segment;
UInt32 numSegments = 1;
if( status == kIOReturnSuccess )
{
UInt64 dma_pos = pos; status = fDMACommand->gen64IOVMSegments( &dma_pos, &segment, &numSegments );
}
if( status == kIOReturnSuccess )
{
if( numSegments != 1 )
{
status = kIOReturnNoMemory;
}
}
if( status == kIOReturnSuccess )
{
phys = segment.fIOVMAddr;
lengthOfSegment = segment.fLength;
}
if( phys == 0 )
{
status = kIOReturnBadArgument; done = true;
break;
}
while( (pos < (length + offset)) && (lengthOfSegment != 0) )
{
UInt32 step = 0;
UInt32 toMap = 0;
if( lengthOfSegment > maxPageClipSize )
step = maxPageClipSize;
else
step = lengthOfSegment;
lengthOfSegment -= step;
if( (pos + step) > (length + offset) )
toMap = length + offset - pos;
else
toMap = step;
if( toMap != 0 )
{
pte++;
if( pte <= ptes_allocated )
{
FWSBP2PTE entry;
entry.segmentLength = OSSwapHostToBigInt16( toMap );
entry.segmentBaseAddressHi = OSSwapHostToBigInt16( ((phys >> 32) & 0x000000000000ffffULL) );
entry.segmentBaseAddressLo = OSSwapHostToBigInt32( (phys & 0x00000000ffffffffULL) );
fPageTableDescriptor->writeBytes( (pte-1) * sizeof(FWSBP2PTE), &entry, sizeof(FWSBP2PTE) );
}
phys += toMap;
pos += toMap;
}
}
}
FWKLOG( ( "IOFireWireSBP2ORB<%p> : number of required PTE's = %d\n", this, pte ) );
if( pte <= ptes_allocated )
{
done = true;
}
else
{
if( fCommandFlags & kFWSBP2CommandFixedSize )
{
status = kIOReturnNoMemory;
done = true;
}
else
{
status = allocatePageTable( pte );
if( status != kIOReturnSuccess )
{
status = kIOReturnNoMemory;
done = true;
}
}
}
}
}
if( status == kIOReturnSuccess )
{
if( pte == 0 )
{
fORBBuffer->dataDescriptorHi = 0;
fORBBuffer->dataDescriptorLo = 0;
fORBBuffer->options &= OSSwapHostToBigInt16(0xfff0); fORBBuffer->dataSize = 0;
fPTECount = 0;
}
else
{
FWSBP2PTE firstEntry;
fPageTableDescriptor->readBytes( 0, &firstEntry, sizeof(FWSBP2PTE) );
if( pte == 1 && !(firstEntry.segmentBaseAddressLo & OSSwapHostToBigInt32(0x00000003)) ) {
fORBBuffer->dataDescriptorHi = 0; fORBBuffer->dataDescriptorLo = firstEntry.segmentBaseAddressLo;
fORBBuffer->options &= OSSwapHostToBigInt16(0xfff0); fORBBuffer->dataSize = firstEntry.segmentLength;
fPTECount = 0;
}
else if( pte * sizeof(FWSBP2PTE) <= fPageTablePhysicalLength )
{
fORBBuffer->dataDescriptorHi = OSSwapHostToBigInt32(fPageTablePhysicalAddress.addressHi); fORBBuffer->dataDescriptorLo = OSSwapHostToBigInt32(fPageTablePhysicalAddress.addressLo);
fORBBuffer->options &= OSSwapHostToBigInt16(0xfff0);
fORBBuffer->options |= OSSwapHostToBigInt16(0x0008); fORBBuffer->dataSize = OSSwapHostToBigInt16(pte);
fPTECount = pte;
}
else
{
fORBBuffer->dataDescriptorHi = OSSwapHostToBigInt32(fPageTablePseudoAddress.addressHi); fORBBuffer->dataDescriptorLo = OSSwapHostToBigInt32(fPageTablePseudoAddress.addressLo);
fORBBuffer->options &= OSSwapHostToBigInt16(0xfff0);
fORBBuffer->options |= OSSwapHostToBigInt16(0x0008); fORBBuffer->dataSize = OSSwapHostToBigInt16(pte);
fPTECount = pte;
}
}
}
if( status != kIOReturnSuccess )
{
completeBufferAddressSpace();
}
fControl->openGate();
return status;
}
IOMemoryDescriptor * IOFireWireSBP2ORB::getCommandBufferDescriptor( void )
{
return fBufferDescriptor;
}
IOReturn IOFireWireSBP2ORB::setCommandBlock( void * buffer, UInt32 length )
{
fControl->closeGate();
UInt32 maxCommandBlockSize = fLogin->getMaxCommandBlockSize();
if( length > maxCommandBlockSize )
return kIOReturnNoMemory;
bzero( &fORBBuffer->commandBlock[0], maxCommandBlockSize );
bcopy( buffer, &fORBBuffer->commandBlock[0], length );
fControl->openGate();
return kIOReturnSuccess;
}
IOReturn IOFireWireSBP2ORB::setCommandBlock( IOMemoryDescriptor * memory )
{
fControl->closeGate();
UInt32 maxCommandBlockSize = fLogin->getMaxCommandBlockSize();
IOByteCount length = memory->getLength();
if( length > maxCommandBlockSize )
return kIOReturnNoMemory;
bzero( &fORBBuffer->commandBlock[0], maxCommandBlockSize );
memory->readBytes(0, &fORBBuffer->commandBlock[0], length );
fControl->openGate();
return kIOReturnSuccess;
}
void IOFireWireSBP2ORB::setCommandFlags( UInt32 flags )
{
fCommandFlags = flags;
}
UInt32 IOFireWireSBP2ORB::getCommandFlags( void )
{
return fCommandFlags;
}
void IOFireWireSBP2ORB::setRefCon( void * refCon )
{
fRefCon = (UInt64)refCon;
}
void * IOFireWireSBP2ORB::getRefCon( void )
{
return (void*)fRefCon;
}
void IOFireWireSBP2ORB::setRefCon64( UInt64 refCon )
{
fRefCon = refCon;
}
UInt64 IOFireWireSBP2ORB::getRefCon64( void )
{
return fRefCon;
}
void IOFireWireSBP2ORB::setMaxPayloadSize( UInt32 maxPayloadSize )
{
fMaxPayloadSize = maxPayloadSize;
}
UInt32 IOFireWireSBP2ORB::getMaxPayloadSize( void )
{
return fMaxPayloadSize;
}
void IOFireWireSBP2ORB::setCommandTimeout( UInt32 timeout )
{
IOReturn ORBTimeoutReinitStatus;
fControl->closeGate();
fTimeoutDuration = timeout;
ORBTimeoutReinitStatus = fTimeoutCommand->reinit( fTimeoutDuration * 1000, IOFireWireSBP2ORB::orbTimeoutStatic, this );
FWPANICASSERT( ORBTimeoutReinitStatus == kIOReturnSuccess );
fControl->openGate();
}
UInt32 IOFireWireSBP2ORB::getCommandTimeout( void )
{
return fTimeoutDuration;
}
void IOFireWireSBP2ORB::setCommandGeneration( UInt32 gen )
{
fGeneration = gen;
}
UInt32 IOFireWireSBP2ORB::getCommandGeneration( void )
{
return fGeneration;
}
void IOFireWireSBP2ORB::getORBAddress( FWAddress * address )
{
if( fCommandFlags & kFWSBP2CommandVirtualORBs )
{
*address = fORBPseudoAddress;
}
else
{
*address = fORBPhysicalAddress;
}
}
void IOFireWireSBP2ORB::setNextORBAddress( FWAddress address )
{
fORBBuffer->nextORBAddressHi = OSSwapHostToBigInt32((UInt32)address.addressHi);
fORBBuffer->nextORBAddressLo = OSSwapHostToBigInt32(address.addressLo);
}
IOFireWireSBP2Login * IOFireWireSBP2ORB::getLogin( void )
{
return fLogin;
}
void IOFireWireSBP2ORB::setToDummy( void )
{
fORBBuffer->options |= OSSwapHostToBigInt16(0x6000);
}
bool IOFireWireSBP2ORB::isAppended( void )
{
return fIsAppended;
}
void IOFireWireSBP2ORB::setIsAppended( bool state )
{
fIsAppended = state;
}
UInt32 IOFireWireSBP2ORB::getFetchAgentWriteRetries( void )
{
return fFetchAgentWriteRetries;
}
void IOFireWireSBP2ORB::setFetchAgentWriteRetries( UInt32 retries )
{
fFetchAgentWriteRetries = retries;
}
UInt32 IOFireWireSBP2ORB::getFetchAgentWriteRetryInterval( void )
{
return fFetchAgentWriteRetryInterval;
}
void IOFireWireSBP2ORB::setFetchAgentWriteRetryInterval( UInt32 interval )
{
fFetchAgentWriteRetryInterval = interval;
}
IOFireWireUnit * IOFireWireSBP2ORB::getFireWireUnit( void )
{
return fLogin->getFireWireUnit();
}
IOFireWireSBP2LUN * IOFireWireSBP2ORB::getFireWireLUN( void )
{
return fLogin->getFireWireLUN();
}
IOReturn IOFireWireSBP2ORB::removeORB( IOFireWireSBP2ORB * orb )
{
return fLogin->removeORB( orb );
}
void IOFireWireSBP2ORB::sendTimeoutNotification( IOFireWireSBP2ORB * orb )
{
fLogin->sendTimeoutNotification( orb );
}