void
SCSIPathSet::removeObject ( const IOSCSIProtocolServices * interface )
{
	
	SCSITargetDevicePath *	member		= NULL;
	OSNumber *				domainID	= NULL;
	UInt32					index		= 0;
	
	STATUS_LOG ( ( "+SCSIPathSet::removeObject\n" ) );
	
	domainID = SCSITargetDevicePath::GetInterfaceDomainIdentifier ( interface );
	
	for ( index = 0; index < count; index++ )
	{
		
		member = ( SCSITargetDevicePath * ) array[index];
		if ( member->GetDomainIdentifier ( )->isEqualTo ( domainID ) )
		{
			
			super::removeObject ( index );
			break;
			
		}
		
	}
	
	STATUS_LOG ( ( "-SCSIPathSet::removeObject\n" ) );
	
}
IOReturn
IOATABlockStorageDriver::doSyncReadWrite ( 
										IOMemoryDescriptor *	buffer,
										UInt32					block,
										UInt32					nblks )
{

	IOReturn			ret;
	IOATACommand *		cmd 	= NULL;
	
	STATUS_LOG ( ( "IOATABlockStorageDriver::doSyncReadWrite entering\n" ) );

	cmd = ataCommandReadWrite ( buffer, block, nblks );
	if ( cmd == NULL )
	{
		
		return kIOReturnNoMemory;
		
	}
	
	ret = syncExecute ( cmd );
		
	STATUS_LOG ( ( "IOATABlockStorageDriver::doSyncReadWrite exiting ret = %ld.\n", ( UInt32 ) ret ) );
	
	return ret;
	
}
bool
SCSIPathSet::setObject ( const SCSITargetDevicePath * path )
{
	
	bool	result = false;
	
	STATUS_LOG ( ( "+SCSIPathSet::setObject\n" ) );
	
	result = member ( path );
	require ( ( result == false ), ErrorExit );
	
	STATUS_LOG ( ( "calling super::setObject()\n" ) );
	
	result = super::setObject ( path );
	
	STATUS_LOG ( ( "-SCSIPathSet::setObject\n" ) );
	
	return result;
	
	
ErrorExit:
	
	
	result = false;
	
	STATUS_LOG ( ( "-SCSIPathSet::setObject\n" ) );
	
	return result;
	
}
bool
SCSIPathSet::member ( const IOSCSIProtocolServices * interface ) const
{
	
	bool					result 		= false;
	OSNumber *				domainID	= NULL;
	SCSITargetDevicePath *	element		= NULL;
	UInt32					index		= 0;
	
	STATUS_LOG ( ( "+SCSIPathSet::member\n" ) );
	
	domainID = SCSITargetDevicePath::GetInterfaceDomainIdentifier ( interface );
	
	for ( index = 0; index < count; index++ )
	{
		
		element = ( SCSITargetDevicePath * ) array[index];
		if ( element->GetDomainIdentifier ( )->isEqualTo ( domainID ) )
		{
			
			STATUS_LOG ( ( "path is member\n" ) );
			result = true;
			break;
			
		}
		
	}
	
	STATUS_LOG ( ( "-SCSIPathSet::member\n" ) );
	
	return result;
	
}
bool
SCSIPathSet::member ( const SCSITargetDevicePath * path ) const
{
	
	bool					result 	= false;
	SCSITargetDevicePath *	element	= NULL;
	UInt32					index	= 0;
	
	STATUS_LOG ( ( "+SCSIPathSet::member\n" ) );
	for ( index = 0; index < count; index++ )
	{
		
		element = ( SCSITargetDevicePath * ) array[index];
		if ( element->GetDomainIdentifier ( )->isEqualTo ( path->GetDomainIdentifier ( ) ) )
		{
			
			STATUS_LOG ( ( "path is member\n" ) );
			result = true;
			break;
			
		}
		
	}
	
	STATUS_LOG ( ( "-SCSIPathSet::member\n" ) );
	
	return result;
	
}
SCSITargetDevicePath *
SCSIPressurePathManager::PortBandwidthGlobals::AllocateBandwidth (
						SCSIPathSet *	pathSet,
						UInt64			bytes )
{
	
	SCSITargetDevicePath *		path		= NULL;
	SCSITargetDevicePath *		result		= NULL;
	UInt32						numPaths	= 0;
	UInt32						index		= 0;
	UInt32						resultIndex	= 0;
	UInt64						bandwidth	= 0xFFFFFFFFFFFFFFFFULL;
	
	STATUS_LOG ( ( "+PortBandwidthGlobals::AllocateBandwidth\n" ) );
	
	// Grab the lock since we'll end up manipulating the table.
	IOLockLock ( fLock );
	
	// Assume we're using the first path.
	result 		= pathSet->getObject ( index );
	numPaths	= pathSet->getCount ( );
	
	// Loop over the passed in possible paths.
	for ( index = 0; index < numPaths; index++ )
	{
		
		UInt32	domainID = 0;
		
		STATUS_LOG ( ( "Getting a path at index = %ld\n", index ) );
		
		path = pathSet->getObject ( index );
		
		domainID = path->GetDomainIdentifier ( )->unsigned32BitValue ( );
		
		// Sanity check
		//check ( domainID < fCapacity );
		
		if ( fListHead[domainID] < bandwidth )
		{
			
			result 		= path;
			bandwidth 	= fListHead[domainID];
			resultIndex	= domainID;
			
		}
		
	}
	
	// Whichever path we chose, charge it with the bandwidth.
	fListHead[resultIndex] += bytes;
	
	// Done manipulating the table. Drop the lock.
	IOLockUnlock ( fLock );
	
	STATUS_LOG ( ( "-PortBandwidthGlobals::AllocateBandwidth\n" ) );
	
	return result;
	
}
IOService *
IOATABlockStorageDriver::instantiateNub ( void )
{
	
	STATUS_LOG ( ( "IOATABlockStorageDriver::instantiateNub entering.\n" ) );
	
	IOService * nub = new IOATABlockStorageDevice;
	
	STATUS_LOG ( ( "IOATABlockStorageDriver::instantiateNub exiting nub = %p.\n", nub ) );
	
	return nub;
	
}
예제 #8
0
/*
 *  DoSCSICommand()
 *  Encapsulate super::SendCommand() to handle unexpected service and
 *  task errors as well as hand off to SCSI SENSE interpreter.
 */
SCSITaskStatus
IOSCSITape::DoSCSICommand(
	SCSITaskIdentifier	request,
	UInt32				timeoutDuration)
{
	SCSITaskStatus		taskStatus		= kSCSITaskStatus_DeliveryFailure;
	SCSIServiceResponse	serviceResponse	= kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
	
	require((request != 0), ErrorExit);
	
	serviceResponse = SendCommand(request, timeoutDuration);
	sense_flags = 0;
	
	if (serviceResponse != kSCSIServiceResponse_TASK_COMPLETE)
	{
		STATUS_LOG("unknown service response: 0x%x", serviceResponse);
		goto ErrorExit;
	}
	else
	{
		taskStatus = GetTaskStatus(request);
		
		if (taskStatus == kSCSITaskStatus_CHECK_CONDITION)
		{
			/* Get and interpret SCSI SENSE information */
			GetSense(request);
		}
		else if (taskStatus != kSCSITaskStatus_GOOD)
		{
			STATUS_LOG("unknown task status: 0x%x", taskStatus);
		}
		else if (taskStatus == kSCSITaskStatus_GOOD)
		{
			/* setup flags for device file closing */
			if (flags & ST_WRITTEN_TOGGLE)
				flags |= ST_WRITTEN;
			else
				flags &= ~ST_WRITTEN;
		}
	}
	
	/* clear the write toggle bit in case the next command is not a
	 * write */
	flags &= ~ST_WRITTEN_TOGGLE;
	
ErrorExit:
	
	return taskStatus;
}
IOReturn
IOATABlockStorageDriver::setWriteCacheState ( bool enabled )
{
	
	IOReturn	status = kIOReturnSuccess;
	
	STATUS_LOG ( ( "IOATABlockStorageDriver::setWriteCacheState called.\n" ) );
	
	if ( activityTickle ( kIOPMSuperclassPolicy1, ( UInt32 ) kIOATAPowerStateActive ) )
	{
		
		status = ataCommandSetFeatures (
								enabled ? kATAEnableWriteCache : kATADisableWriteCache,
								0,
								0,
								0,
								0,
								mATAFlagImmediate,
								true );
		
	}
	
	else
	{
		
		status = kIOReturnNotResponding;
		
	}
	
	return status;
	
}
IOReturn
IOATABlockStorageDriver::getWriteCacheState ( bool * enabled )
{
	
	IOReturn	status = kIOReturnSuccess;
	
	STATUS_LOG ( ( "IOATABlockStorageDriver::getWriteCacheState called.\n" ) );

	if ( activityTickle ( kIOPMSuperclassPolicy1, ( UInt32 ) kIOATAPowerStateActive ) )
	{
		
		status = identifyATADevice ( );
		
		if ( status == kIOReturnSuccess )
		{
			
			// Get write cache enabled bit. It's in word 85, bit 5
			*enabled = fDeviceIdentifyData[kATAIdentifyCommandExtension2] & kATAWriteCacheEnabledMask;
			
		}
	
	}
	
	else
	{
		
		status = kIOReturnNotResponding;
		
	}
	
	return status;
	
}
SCSIPathSet *
SCSIPathSet::withCapacity ( unsigned int capacity )
{
	
	SCSIPathSet *	set 	= NULL;
	bool			result	= false;
	
	STATUS_LOG ( ( "+SCSIPathSet::withCapacity\n" ) );
	
	set = OSTypeAlloc ( SCSIPathSet );
	require_nonzero ( set, ErrorExit );
	
	result = set->initWithCapacity ( capacity );
	require ( result, ReleaseSet );
	
	return set;
	
	
ReleaseSet:
	
	
	require_nonzero_quiet ( set, ErrorExit );
	set->release ( );
	set = NULL;
	
	
ErrorExit:
	
	
	return set;
	
}
void
SCSIPressurePathManager::free ( void )
{
	
	STATUS_LOG ( ( "SCSIPressurePathManager::free\n" ) );
	
	if ( fPathSet != NULL )
	{
		
		fPathSet->release ( );
		fPathSet = NULL;
		
	}
	
	if ( fInactivePathSet != NULL )
	{
		
		fInactivePathSet->release ( );
		fInactivePathSet = NULL;
		
	}
	
	if ( fLock != NULL )
	{
		
		IOLockFree ( fLock );
		fLock = NULL;
		
	}
	
	super::free ( );
	
}
SCSITargetDevicePath *
SCSIPathSet::getObjectWithInterface ( const IOSCSIProtocolServices * interface ) const
{
	
	SCSITargetDevicePath *	element		= NULL;
	SCSITargetDevicePath *	result		= NULL;
	OSNumber *				domainID	= NULL;
	UInt32					index		= 0;
	
	STATUS_LOG ( ( "+SCSIPathSet::getObjectWithInterface\n" ) );
	
	domainID = SCSITargetDevicePath::GetInterfaceDomainIdentifier ( interface );
	
	for ( index = 0; index < count; index++ )
	{
		
		element = ( SCSITargetDevicePath * ) array[index];
		if ( element->GetDomainIdentifier ( )->isEqualTo ( domainID ) )
		{
			
			result = element;
			break;
			
		}
		
	}
	
	return result;
	
}
예제 #14
0
/*
 *  GetSenseInformation
 *
 *  Attempt to get SCSI sense information either from the Auto sense
 *  mechanism or by querying manually.
 */
void
IOSCSITape::GetSense(SCSITaskIdentifier request)
{
	SCSI_Sense_Data		senseBuffer = { 0 };
	bool				validSense = false;
	SCSIServiceResponse	serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
	
	IOMemoryDescriptor *bufferDesc = IOMemoryDescriptor::withAddress((void *)&senseBuffer, 
																	 sizeof(senseBuffer), 
																	 kIODirectionIn);
	
	if (GetTaskStatus(request) == kSCSITaskStatus_CHECK_CONDITION)
	{
		validSense = GetAutoSenseData(request, &senseBuffer);
		
		if (validSense == false)
		{
			if (REQUEST_SENSE(request, bufferDesc, kSenseDefaultSize, 0) == true)
				serviceResponse = SendCommand(request, kTenSecondTimeoutInMS);
			
			if (serviceResponse == kSCSIServiceResponse_TASK_COMPLETE)
				validSense = true;
		}
		
		if (validSense == true)
			InterpretSense(&senseBuffer);
		else
			STATUS_LOG("invalid or unretrievable SCSI SENSE");
	}
	
	bufferDesc->release();
}
AppleSCSIPDT03Emulator *
AppleSCSIPDT03Emulator::Create ( void )
{
	
	AppleSCSIPDT03Emulator *	logicalUnit = NULL;
	bool						result		= false;
	
	STATUS_LOG ( ( "AppleSCSIPDT03Emulator::Create\n" ) );
	
	logicalUnit = OSTypeAlloc ( AppleSCSIPDT03Emulator );
	require_nonzero ( logicalUnit, ErrorExit );
	
	result = logicalUnit->init ( );
	require ( result, ReleaseLogicalUnit );
	
	return logicalUnit;
	
	
ReleaseLogicalUnit:
	
	
	logicalUnit->release ( );
	
	
ErrorExit:
	
	
	return NULL;
	
}
IOReturn
IOATABlockStorageDriver::doFormatMedia ( UInt64 byteCapacity )
{
	
	STATUS_LOG ( ( "IOATABlockStorageDriver::doFormatMedia called.\n" ) );
	return kIOReturnUnsupported;
	
}
char *
IOATABlockStorageDriver::getRevisionString ( void )
{

	STATUS_LOG ( ( "IOATABlockStorageDriver::getRevisionString called.\n" ) );
	return fRevision;
	
}
char *
IOATABlockStorageDriver::getVendorString ( void )
{

	STATUS_LOG ( ( "IOATABlockStorageDriver::getVendorString called.\n" ) );
	return NULL;
	
}
char *
IOATABlockStorageDriver::getAdditionalDeviceInfoString ( void )
{

	STATUS_LOG ( ( "IOATABlockStorageDriver::getAdditionalDeviceInfoString called.\n" ) );
	return ( "[ATA]" );
	
}
char *
IOATABlockStorageDriver::getProductString ( void )
{

	STATUS_LOG ( ( "IOATABlockStorageDriver::getProductString called.\n" ) );
	return fModel;
	
}
IOReturn
IOATABlockStorageDriver::doStop ( void )
{
	
	STATUS_LOG ( ( "IOATABlockStorageDriver::doStop called.\n" ) );
	return kIOReturnSuccess;
	
}
IOReturn
IOATABlockStorageDriver::doLockUnlockMedia ( bool doLock )
{
	
	STATUS_LOG ( ( "IOATABlockStorageDriver::doLockUnlockMedia called.\n" ) );
	return kIOReturnUnsupported;	// No removable ATA device support.
	
}
bool
SCSIPressurePathManager::AddPath ( IOSCSIProtocolServices * interface )
{
	
	bool							result 	= false;
	SCSITargetDevicePath *			path	= NULL;
	OSDictionary *					dict	= NULL;
	PortBandwidthGlobals *			bw		= NULL;
	
	STATUS_LOG ( ( "SCSIPressurePathManager::AddPath\n" ) );
	
	require_nonzero ( interface, ErrorExit );
	
	path = SCSITargetDevicePath::Create ( this, interface );
	require_nonzero ( path, ErrorExit );
	
	bw = PortBandwidthGlobals::GetSharedInstance ( );
	bw->AddSCSIPort ( path->GetDomainIdentifier ( )->unsigned32BitValue ( ) );
	
	STATUS_LOG ( ( "Registering callback handler\n" ) );
	
	interface->RegisterSCSITaskCompletionRoutine ( &SCSITargetDevicePathManager::PathTaskCallback );
	
	dict = path->GetStatistics ( );
	
	STATUS_LOG ( ( "Got path stats, count = %ld\n", dict->getCount ( ) ) );
	
	fStatistics->setObject ( dict );
	
	STATUS_LOG ( ( "fStatistics array has %ld members\n", fStatistics->getCount ( ) ) );
	
	IOLockLock ( fLock );
	result = fPathSet->setObject ( path );
	IOLockUnlock ( fLock );
	
	path->release ( );
	path = NULL;
	
	
ErrorExit:
	
	
	return result;
	
}
void
SCSIPressurePathManager::ActivatePath ( IOSCSIProtocolServices * interface )
{
	
	bool					result 	= false;
	SCSITargetDevicePath *	path	= NULL;
	
	STATUS_LOG ( ( "SCSIPressurePathManager::ActivatePath\n" ) );
	
	require_nonzero ( interface, ErrorExit );
	
	IOLockLock ( fLock );
	
	result = fInactivePathSet->member ( interface );
	if ( result == true )
	{
		
		path = fInactivePathSet->getObjectWithInterface ( interface );
		if ( path != NULL )
		{
			
			path->retain ( );
			path->Activate ( );
			fInactivePathSet->removeObject ( interface );
			fPathSet->setObject ( path );
			path->release ( );
			path = NULL;
			
		}
		
	}
	
	else
	{
		
		result = fPathSet->member ( interface );
		if ( result == false )
		{
			
			IOLockUnlock ( fLock );
			AddPath ( interface );
			goto Exit;
			
		}
		
	}
	
	IOLockUnlock ( fLock );
	
	
ErrorExit:
Exit:
	
	
	return;
	
}
IOReturn
IOATABlockStorageDriver::reportMaxValidBlock ( UInt64 * maxBlock )
{
	
	UInt64		diskCapacity = 0;
	
	assert ( fATADevice && maxBlock );
	
	STATUS_LOG ( ( "IOATABlockStorageDriver::reportMaxValidBlock called.\n" ) );
	
	doGetFormatCapacities ( &diskCapacity, 1 );
	
	*maxBlock = ( diskCapacity / kATADefaultSectorSize ) - 1;
	
	STATUS_LOG ( ( "IOATABlockStorageDriver::reportMaxValidBlock maxBlock = %ld.\n", *maxBlock ) );
	
	return kIOReturnSuccess;
	
}
IOReturn
IOATABlockStorageDriver::reportLockability ( bool * isLockable )
{
	
	STATUS_LOG ( ( "IOATABlockStorageDriver::reportLockability called.\n" ) );
	
	*isLockable = false;
	return kIOReturnSuccess;
	
}
IOReturn
IOATABlockStorageDriver::reportEjectability ( bool * isEjectable )
{
	
	STATUS_LOG ( ( "IOATABlockStorageDriver::reportEjectability called.\n" ) );
	
	*isEjectable = (fATASocketType == kPCCardSocket);
	return kIOReturnSuccess;
	
}
IOReturn
IOATABlockStorageDriver::reportWriteProtection ( bool * isWriteProtected )
{

	STATUS_LOG ( ( "IOATABlockStorageDriver::reportWriteProtection called.\n" ) );

	*isWriteProtected = false;
	return kIOReturnSuccess;
	
}
IOReturn
IOATABlockStorageDriver::doSynchronizeCache ( void )
{
	
	IOReturn			status 	= kIOReturnSuccess;
	IOATACommand *		cmd 	= NULL;
	
	STATUS_LOG ( ( "IOATABlockStorageDriver::doSynchronizeCache called.\n" ) );
	
	if ( fATASocketType == kPCCardSocket )
	{
		
		// Device doesnÕt support flush cache. DonÕt send the command.
		fNumCommandsOutstanding--;
		status = kIOReturnSuccess;
		goto Exit;
		
	}
	
	cmd = ataCommandFlushCache ( );
	
	// Do we have a valid command?
	if ( cmd == NULL )
	{
		
		// Return no memory error.
		fNumCommandsOutstanding--;
		status = kIOReturnNoMemory;
		goto Exit;
		
	}
	
	// Send the command to flush the cache.
	status = syncExecute ( cmd, kATATimeout1Minute, 0 );	

Exit:
	
	STATUS_LOG ( ( "IOATABlockStorageDriver::doSynchronizeCache returning status = %ld.\n", ( UInt32 ) status ) );
	
	return status;
	
}
IOReturn
IOATABlockStorageDriver::reportBlockSize ( UInt64 * blockSize )
{
	
	STATUS_LOG ( ( "IOATABlockStorageDriver::reportBlockSize called.\n" ) );
	
	*blockSize = kATADefaultSectorSize;
	
	return kIOReturnSuccess;
	
}