/* * Copyright (c) 1998-2001 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * The contents of this file constitute Original Code as defined in and * are subject to the Apple Public Source License Version 1.1 (the * "License"). You may not use this file except in compliance with the * License. Please obtain a copy of the License at * http://www.apple.com/publicsource and read it before using this file. * * This Original Code and all software distributed under the License are * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License. * * @APPLE_LICENSE_HEADER_END@ */ #include #include #include #include #include #if ( SCSI_RBC_DEVICE_DEBUGGING_LEVEL >= 1 ) #define PANIC_NOW(x) IOPanic x #else #define PANIC_NOW(x) #endif #if ( SCSI_RBC_DEVICE_DEBUGGING_LEVEL >= 2 ) #define ERROR_LOG(x) IOLog x #else #define ERROR_LOG(x) #endif #if ( SCSI_RBC_DEVICE_DEBUGGING_LEVEL >= 3 ) #define STATUS_LOG(x) IOLog x #else #define STATUS_LOG(x) #endif #define kMaxRetryCount 8 #define kModeSenseWriteProtectBufferSize 17 #define super IOSCSIPrimaryCommandsDevice OSDefineMetaClass ( IOSCSIReducedBlockCommandsDevice, IOSCSIPrimaryCommandsDevice ); OSDefineAbstractStructors ( IOSCSIReducedBlockCommandsDevice, IOSCSIPrimaryCommandsDevice ); #pragma mark - Public Methods bool IOSCSIReducedBlockCommandsDevice::InitializeDeviceSupport( void ) { bool setupSuccessful = false; // Initialize the device characteristics flags fMediaIsRemovable = false; // Initialize the medium characteristics fMediaChanged = false; fMediaPresent = false; fMediaIsRemovable = false; fMediaIsWriteProtected = true; STATUS_LOG ( ( "IOSCSIReducedBlockCommandsDevice::InitializeDeviceSupport called\n" ) ); fIOSCSIReducedBlockCommandsDeviceReserved = ( IOSCSIReducedBlockCommandsDeviceExpansionData * ) IOMalloc ( sizeof ( IOSCSIReducedBlockCommandsDeviceExpansionData ) ); if ( fIOSCSIReducedBlockCommandsDeviceReserved == NULL ) { goto ERROR_EXIT; } bzero ( fIOSCSIReducedBlockCommandsDeviceReserved, sizeof ( IOSCSIReducedBlockCommandsDeviceExpansionData ) ); // Make sure the drive is ready for us! if ( ClearNotReadyStatus ( ) == false ) { goto ERROR_EXIT; } setupSuccessful = DetermineDeviceCharacteristics ( ); if ( setupSuccessful == true ) { fPollingThread = thread_call_allocate ( ( thread_call_func_t ) IOSCSIReducedBlockCommandsDevice::sPollForMedia, ( thread_call_param_t ) this ); if ( fPollingThread == NULL ) { ERROR_LOG ( ( "fPollingThread allocation failed.\n" ) ); setupSuccessful = false; goto ERROR_EXIT; } InitializePowerManagement ( GetProtocolDriver ( ) ); } STATUS_LOG ( ( "IOSCSIReducedBlockCommandsDevice::InitializeDeviceSupport setupSuccessful = %d\n", setupSuccessful ) ); return setupSuccessful; ERROR_EXIT: if ( fIOSCSIReducedBlockCommandsDeviceReserved != NULL ) { IOFree ( fIOSCSIReducedBlockCommandsDeviceReserved, sizeof ( IOSCSIReducedBlockCommandsDeviceExpansionData ) ); fIOSCSIReducedBlockCommandsDeviceReserved = NULL; } return setupSuccessful; } void IOSCSIReducedBlockCommandsDevice::StartDeviceSupport( void ) { if( fMediaIsRemovable == false ) { UInt32 attempts = 0; // We have a fixed disk, so make sure we determine its state // before we create the layer above us. do { PollForMedia(); } while ( ( fMediaPresent == false ) && ( ++attempts < kMaxRetryCount ) && ( isInactive ( ) == false ) ); } else { // Removable media - start polling EnablePolling(); } CreateStorageServiceNub(); } void IOSCSIReducedBlockCommandsDevice::SuspendDeviceSupport( void ) { DisablePolling(); } void IOSCSIReducedBlockCommandsDevice::ResumeDeviceSupport( void ) { EnablePolling(); } void IOSCSIReducedBlockCommandsDevice::StopDeviceSupport( void ) { DisablePolling(); } void IOSCSIReducedBlockCommandsDevice::TerminateDeviceSupport( void ) { STATUS_LOG ( ( "IOSCSIReducedBlockCommandsDevice::cleanUp called.\n" ) ); if ( fPollingThread != NULL ) { thread_call_free ( fPollingThread ); fPollingThread = NULL; } // Release all memory/objects associated with the reserved fields. if ( fPowerDownNotifier != NULL ) { // remove() will also call release() on this object (IONotifier). // See IONotifier.h for more info. fPowerDownNotifier->remove ( ); fPowerDownNotifier = NULL; } // Release the reserved structure. if ( fIOSCSIReducedBlockCommandsDeviceReserved != NULL ) { IOFree ( fIOSCSIReducedBlockCommandsDeviceReserved, sizeof ( IOSCSIReducedBlockCommandsDeviceExpansionData ) ); fIOSCSIReducedBlockCommandsDeviceReserved = NULL; } } bool IOSCSIReducedBlockCommandsDevice::CreateCommandSetObjects ( void ) { STATUS_LOG ( ( "IOSCSIReducedBlockCommandsDevice::CreateCommandSetObjects called\n" ) ); fSCSIReducedBlockCommandObject = SCSIReducedBlockCommands::CreateSCSIReducedBlockCommandObject ( ); if ( fSCSIReducedBlockCommandObject == NULL ) { ERROR_LOG ( ( "IOSCSIReducedBlockCommandsDevice::start exiting false, RBC object not created\n" ) ); return false; } return true; } void IOSCSIReducedBlockCommandsDevice::FreeCommandSetObjects ( void ) { STATUS_LOG ( ( "IOSCSIReducedBlockCommandsDevice::FreeCommandSetObjects called\n" ) ); if ( fSCSIReducedBlockCommandObject ) { fSCSIReducedBlockCommandObject->release ( ); fSCSIReducedBlockCommandObject = NULL; } } SCSIReducedBlockCommands * IOSCSIReducedBlockCommandsDevice::GetSCSIReducedBlockCommandObject ( void ) { return fSCSIReducedBlockCommandObject; } SCSIPrimaryCommands * IOSCSIReducedBlockCommandsDevice::GetSCSIPrimaryCommandObject ( void ) { return OSDynamicCast ( SCSIPrimaryCommands, GetSCSIReducedBlockCommandObject ( ) ); } bool IOSCSIReducedBlockCommandsDevice::ClearNotReadyStatus ( void ) { SCSI_Sense_Data senseBuffer; IOMemoryDescriptor * bufferDesc; SCSITaskIdentifier request; bool driveReady = false; bool result = true; SCSIServiceResponse serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE; STATUS_LOG ( ( "%s::%s called\n", getName ( ), __FUNCTION__ ) ); bufferDesc = IOMemoryDescriptor::withAddress ( ( void * ) &senseBuffer, kSenseDefaultSize, kIODirectionIn ); request = GetSCSITask ( ); do { if ( TEST_UNIT_READY ( request ) == true ) { // The command was successfully built, now send it serviceResponse = SendCommand ( request, 0 ); } else { PANIC_NOW ( ( "IOSCSIBlockCommandsDevice::ClearNotReadyStatus malformed command" ) ); } if ( serviceResponse == kSCSIServiceResponse_TASK_COMPLETE ) { bool validSense = false; if ( GetTaskStatus ( request ) == kSCSITaskStatus_CHECK_CONDITION ) { validSense = GetAutoSenseData ( request, &senseBuffer ); if ( validSense == false ) { if ( REQUEST_SENSE ( request, bufferDesc, kSenseDefaultSize ) == true ) { // The command was successfully built, now send it serviceResponse = SendCommand ( request, 0 ); } else { PANIC_NOW ( ( "IOSCSIBlockCommandsDevice::ClearNotReadyStatus malformed command" ) ); } if ( serviceResponse == kSCSIServiceResponse_TASK_COMPLETE ) { validSense = true; } } if ( validSense == true ) { if ( ( ( senseBuffer.SENSE_KEY & kSENSE_KEY_Mask ) == kSENSE_KEY_NOT_READY ) && ( senseBuffer.ADDITIONAL_SENSE_CODE == 0x04 ) && ( senseBuffer.ADDITIONAL_SENSE_CODE_QUALIFIER == 0x01 ) ) { STATUS_LOG ( ( "%s::drive not ready\n", getName ( ) ) ); driveReady = false; IOSleep ( 200 ); } else if ( ( ( senseBuffer.SENSE_KEY & kSENSE_KEY_Mask ) == kSENSE_KEY_NOT_READY ) && ( senseBuffer.ADDITIONAL_SENSE_CODE == 0x04 ) && ( senseBuffer.ADDITIONAL_SENSE_CODE_QUALIFIER == 0x02 ) ) { // The drive needs to be spun up. Issue a START_STOP_UNIT to it. if ( START_STOP_UNIT ( request, 0x00, 0x00, 0x00, 0x01 ) == true ) { serviceResponse = SendCommand ( request, 0 ); } } else { driveReady = true; STATUS_LOG ( ( "%s::drive READY\n", getName ( ) ) ); } STATUS_LOG ( ( "sense data: %01x, %02x, %02x\n", ( senseBuffer.SENSE_KEY & kSENSE_KEY_Mask ), senseBuffer.ADDITIONAL_SENSE_CODE, senseBuffer.ADDITIONAL_SENSE_CODE_QUALIFIER ) ); } } else { driveReady = true; } } else { // the command failed - perhaps the device was hot unplugged // give other threads some time to run. IOSleep ( 200 ); } // check isInactive in case device was hot unplugged during sleep // and we are in an infinite loop here } while ( ( driveReady == false ) && ( isInactive ( ) == false ) ); bufferDesc->release ( ); ReleaseSCSITask ( request ); result = isInactive ( ) ? false : true; return result; } #pragma mark - Protected Methods void IOSCSIReducedBlockCommandsDevice::EnablePolling ( void ) { AbsoluteTime time; // No reason to start a thread if we've been termintated if ( ( isInactive ( ) == false ) && fPollingThread ) { // Retain ourselves so that this object doesn't go away // while we are polling retain ( ); clock_interval_to_deadline ( 1000, kMillisecondScale, &time ); thread_call_enter_delayed ( fPollingThread, time ); } } void IOSCSIReducedBlockCommandsDevice::DisablePolling ( void ) { // Cancel the thread if it is running if ( thread_call_cancel ( fPollingThread ) ) { // It was running, so we balance out the retain() // with a release() release ( ); } } bool IOSCSIReducedBlockCommandsDevice::DetermineDeviceCharacteristics ( void ) { SCSIServiceResponse serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE; UInt8 loop; UInt8 inquiryBufferCount = sizeof ( SCSICmd_INQUIRY_StandardData ); SCSICmd_INQUIRY_StandardData * inquiryBuffer = NULL; IOMemoryDescriptor * bufferDesc = NULL; SCSITaskIdentifier request = NULL; bool succeeded = false; STATUS_LOG ( ( "%s::%s called\n", getName ( ), __FUNCTION__ ) ); inquiryBuffer = ( SCSICmd_INQUIRY_StandardData * ) IOMalloc ( inquiryBufferCount ); if ( inquiryBuffer == NULL ) { STATUS_LOG ( ( "%s: Couldn't allocate Inquiry buffer.\n", getName ( ) ) ); goto ErrorExit; } bufferDesc = IOMemoryDescriptor::withAddress ( inquiryBuffer, inquiryBufferCount, kIODirectionIn ); if ( bufferDesc == NULL ) { ERROR_LOG ( ( "%s: Couldn't alloc Inquiry buffer: ", getName() ) ); goto ErrorExit; } request = GetSCSITask( ); if ( request == NULL ) { goto ErrorExit; } for ( loop = 0; ( loop < kMaxRetryCount ) && ( isInactive ( ) == false ) ; loop++ ) { if ( INQUIRY( request, bufferDesc, 0, 0, 0x00, inquiryBufferCount) == true ) { // The command was successfully built, now send it serviceResponse = SendCommand ( request, 0 ); } else { PANIC_NOW ( ( "IOSCSIBlockCommandsDevice::DetermineDeviceCharacteristics malformed command" ) ); goto ErrorExit; } if ( ( serviceResponse == kSCSIServiceResponse_TASK_COMPLETE ) && ( GetTaskStatus ( request ) == kSCSITaskStatus_GOOD ) ) { break; } } if ( ( serviceResponse != kSCSIServiceResponse_TASK_COMPLETE ) || ( GetTaskStatus ( request ) != kSCSITaskStatus_GOOD ) ) { goto ErrorExit; } succeeded = true; if ( ( inquiryBuffer->RMB & kINQUIRY_PERIPHERAL_RMB_BitMask ) == kINQUIRY_PERIPHERAL_RMB_MediumRemovable ) { STATUS_LOG ( ( "Media is removable\n" ) ); fMediaIsRemovable = true; } else { STATUS_LOG ( ( "Media is NOT removable\n" ) ); fMediaIsRemovable = false; } STATUS_LOG ( ( "IOSCSIReducedBlockCommandsDevice::DetermineDeviceCharacteristics exiting\n" ) ); ErrorExit: if ( request ) { ReleaseSCSITask ( request ); request = NULL; } if ( bufferDesc ) { bufferDesc->release ( ); bufferDesc = NULL; } if ( inquiryBuffer ) { IOFree( ( void *) inquiryBuffer, inquiryBufferCount ); inquiryBuffer = NULL; } return succeeded; } void IOSCSIReducedBlockCommandsDevice::SetMediaCharacteristics ( UInt32 blockSize, UInt32 blockCount ) { STATUS_LOG ( ( "%s::%s called\n", getName ( ), __FUNCTION__ ) ); STATUS_LOG ( ( "mediaBlockSize = %ld, blockCount = %ld\n", blockSize, blockCount ) ); fMediaBlockSize = blockSize; fMediaBlockCount = blockCount; STATUS_LOG ( ( "%s::%s exiting\n", getName ( ), __FUNCTION__ ) ); } void IOSCSIReducedBlockCommandsDevice::ResetMediaCharacteristics ( void ) { STATUS_LOG ( ( "%s::%s called\n", getName ( ), __FUNCTION__ ) ); fMediaBlockSize = 0; fMediaBlockCount = 0; fMediaPresent = false; STATUS_LOG ( ( "%s::%s exiting\n", getName ( ), __FUNCTION__ ) ); } void IOSCSIReducedBlockCommandsDevice::CreateStorageServiceNub ( void ) { STATUS_LOG ( ( "%s::%s entering.\n", getName ( ), __FUNCTION__ ) ); IOService * nub = new IOReducedBlockServices; if ( nub == NULL ) { PANIC_NOW ( ( "IOSCSIReducedBlockCommandsDevice::createStorageServiceNub failed\n" ) ); } nub->init ( ); if ( !nub->attach ( this ) ) { // panic since the nub can't attach PANIC_NOW ( ( "IOSCSIReducedBlockCommandsDevice::createStorageServiceNub unable to attach nub" ) ); } nub->registerService ( ); STATUS_LOG ( ( "%s::%s exiting.\n", getName ( ), __FUNCTION__ ) ); nub->release(); } void IOSCSIReducedBlockCommandsDevice::PollForMedia ( void ) { SCSIServiceResponse serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE; SCSI_Sense_Data senseBuffer; UInt32 capacityData[2]; IOMemoryDescriptor * bufferDesc; SCSITaskIdentifier request; bool mediaFound = false; bool validSense; SCSITaskStatus taskStatus; bufferDesc = IOMemoryDescriptor::withAddress ( ( void * ) &senseBuffer, kSenseDefaultSize, kIODirectionIn ); if ( bufferDesc == NULL ) { return; } request = GetSCSITask ( ); // Do a TEST_UNIT_READY to generate sense data if ( TEST_UNIT_READY ( request ) == true ) { // The command was successfully built, now send it serviceResponse = SendCommand ( request, 0 ); } else { PANIC_NOW(( "IOSCSIReducedBlockCommandsDevice::PollForMedia malformed command" )); } if ( serviceResponse == kSCSIServiceResponse_TASK_COMPLETE ) { if ( GetTaskStatus ( request ) == kSCSITaskStatus_CHECK_CONDITION ) { validSense = GetAutoSenseData( request, &senseBuffer ); if ( validSense == false ) { // Get the sense data to determine if media is present. // This will eventually use the autosense data if the // Transport Protocol supports it else issue the REQUEST_SENSE. if ( REQUEST_SENSE ( request, bufferDesc, kSenseDefaultSize ) == false ) { // The command was successfully built, now send it serviceResponse = SendCommand ( request, 0 ); } else { PANIC_NOW(( "IOSCSIReducedBlockCommandsDevice::PollForMedia malformed command" )); } } if ( ( senseBuffer.ADDITIONAL_SENSE_CODE == 0x00 ) && ( senseBuffer.ADDITIONAL_SENSE_CODE_QUALIFIER == 0x00 ) ) { mediaFound = true; } } else { mediaFound = true; } } bufferDesc->release ( ); if ( mediaFound == false ) { ReleaseSCSITask ( request ); return; } // If we got here, then we have found media if ( fMediaIsRemovable == true ) { // Lock removable media if ( PREVENT_ALLOW_MEDIUM_REMOVAL ( request, 1 ) == true ) { // The command was successfully built, now send it serviceResponse = SendCommand ( request, 0 ); } else { PANIC_NOW(( "IOSCSIReducedBlockCommandsDevice::PollForMedia malformed command" )); } } bufferDesc = IOMemoryDescriptor::withAddress ( capacityData, 8, kIODirectionIn ); // We found media, Get its capacity if ( READ_CAPACITY ( request, bufferDesc ) == true ) { // The command was successfully built, now send it serviceResponse = SendCommand ( request, 0 ); } else { PANIC_NOW(( "IOSCSIReducedBlockCommandsDevice::PollForMedia malformed command" )); } taskStatus = GetTaskStatus ( request ); ReleaseSCSITask ( request ); bufferDesc->release ( ); if ( ( serviceResponse == kSCSIServiceResponse_TASK_COMPLETE ) && ( taskStatus == kSCSITaskStatus_GOOD ) ) { SetMediaCharacteristics ( OSSwapBigToHostInt32 ( capacityData[1] ), OSSwapBigToHostInt32 ( capacityData[0] ) + 1 ); STATUS_LOG ( ( "%s: Media capacity: %x and block size: %x\n", getName ( ), fMediaBlockCount, fMediaBlockSize ) ); } else { ERROR_LOG ( ( "%s: Read Capacity failed\n", getName() ) ); return; } CheckWriteProtection ( ); fMediaPresent = true; fMediaChanged = true; // Message up the chain that we have media messageClients ( kIOMessageMediaStateHasChanged, ( void * ) kIOMediaStateOnline ); } void IOSCSIReducedBlockCommandsDevice::CheckWriteProtection ( void ) { SCSIServiceResponse serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE; UInt8 modeSenseBuffer[kModeSenseWriteProtectBufferSize]; IOMemoryDescriptor * bufferDesc; SCSITaskIdentifier request; SCSICmdField1Bit DBD; STATUS_LOG ( ( "IOSCSIReducedBlockCommandsDevice::checkWriteProtection called\n" ) ); bzero ( modeSenseBuffer, kModeSenseWriteProtectBufferSize ); bufferDesc = IOMemoryDescriptor::withAddress ( modeSenseBuffer, kModeSenseWriteProtectBufferSize, kIODirectionIn ); request = GetSCSITask ( ); DBD = 1; /* Disable block descriptors */ LOOP: if ( MODE_SENSE_6 ( request, bufferDesc, DBD, 0x00, 0x06, kModeSenseWriteProtectBufferSize ) == true ) { // The command was successfully built, now send it serviceResponse = SendCommand ( request, 0 ); } else { PANIC_NOW ( ( "IOSCSIReducedBlockCommandsDevice::CheckWriteProtection malformed command" ) ); } if ( ( serviceResponse == kSCSIServiceResponse_TASK_COMPLETE ) && ( GetTaskStatus ( request ) == kSCSITaskStatus_GOOD ) ) { STATUS_LOG ( ( "%s: Returned Mode sense data: ", getName ( ) ) ); #if ( SCSI_RBC_DEVICE_DEBUGGING_LEVEL >=3 ) for ( UInt32 i = 0; i < kModeSenseWriteProtectBufferSize; i++ ) { STATUS_LOG ( ( "%x: ", modeSenseBuffer[i] ) ); } STATUS_LOG ( ( "\n" ) ); #endif // DEBUG if ( ( modeSenseBuffer[15] & 0x04 ) != 0 ) { fMediaIsWriteProtected = true; } else { fMediaIsWriteProtected = false; } } else { if ( DBD == 1 ) { // Retry with DBD=0 DBD = 0; goto LOOP; } STATUS_LOG ( ( "%s: Mode Sense failed with service response = %x\n", getName ( ), serviceResponse ) ); // The mode sense failed, mark as write protected to be safe. fMediaIsWriteProtected = true; } bufferDesc->release ( ); ReleaseSCSITask ( request ); } void IOSCSIReducedBlockCommandsDevice::AsyncReadWriteComplete ( SCSITaskIdentifier request ) { void * clientData; IOReturn status; UInt64 actCount = 0; IOSCSIReducedBlockCommandsDevice * taskOwner; SCSITask * scsiRequest; scsiRequest = OSDynamicCast( SCSITask, request ); if ( scsiRequest == NULL ) { PANIC_NOW(( "IOSCSIReducedBlockCommandsDevice::AsyncReadWriteComplete scsiRequest==NULL." )); } // Extract the client data from the SCSITask STATUS_LOG ( ( "IOSCSIReducedBlockCommandsDevice::AsyncReadWriteComplete retrieve clientData.\n" ) ); clientData = scsiRequest->GetApplicationLayerReference(); if ( ( scsiRequest->GetServiceResponse ( ) == kSCSIServiceResponse_TASK_COMPLETE ) && ( scsiRequest->GetTaskStatus ( ) == kSCSITaskStatus_GOOD ) ) { // Our status is good, so return a success status = kIOReturnSuccess; actCount = scsiRequest->GetRealizedDataTransferCount ( ); } else { status = kIOReturnError; } STATUS_LOG ( ( "IOSCSIReducedBlockCommandsDevice::AsyncReadWriteComplete retrieve taskowner.\n" ) ); taskOwner = OSDynamicCast ( IOSCSIReducedBlockCommandsDevice, scsiRequest->GetTaskOwner ( ) ); if ( taskOwner == NULL ) { PANIC_NOW ( ( "IOSCSIReducedBlockCommandsDevice::AsyncReadWriteComplete taskOwner==NULL." ) ); } STATUS_LOG ( ( "IOSCSIReducedBlockCommandsDevice::AsyncReadWriteComplete release SCSITask.\n" ) ); taskOwner->ReleaseSCSITask ( request ); STATUS_LOG ( ( "IOSCSIReducedBlockCommandsDevice::AsyncReadWriteComplete call IOBlockStorageServices::Complete.\n" ) ); IOReducedBlockServices::AsyncReadWriteComplete( clientData, status, actCount ); } // Perform the Synchronous Read Request IOReturn IOSCSIReducedBlockCommandsDevice::IssueRead ( IOMemoryDescriptor * buffer, UInt64 startBlock, UInt64 blockCount ) { SCSIServiceResponse serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE; SCSITaskIdentifier request; IOReturn status = kIOReturnError; STATUS_LOG ( ( "%s: syncRead Attempted\n", getName() ) ); request = GetSCSITask ( ); if ( READ_10 ( request, buffer, fMediaBlockSize, ( SCSICmdField4Byte ) startBlock, ( SCSICmdField2Byte ) blockCount ) == true ) { // The command was successfully built, now send it serviceResponse = SendCommand ( request, 0 ); } else { PANIC_NOW(( "IOSCSIReducedBlockCommandsDevice::IssueRead malformed command" )); } if ( ( serviceResponse == kSCSIServiceResponse_TASK_COMPLETE ) && ( GetTaskStatus ( request ) == kSCSITaskStatus_GOOD ) ) { status = kIOReturnSuccess; } ReleaseSCSITask ( request ); return status; } // Perform the Asynchronous Read Request IOReturn IOSCSIReducedBlockCommandsDevice::IssueRead ( IOMemoryDescriptor * buffer, UInt64 startBlock, UInt64 blockCount, void * clientData ) { IOReturn status = kIOReturnSuccess; SCSITaskIdentifier request; STATUS_LOG ( ( "%s: asyncRead Attempted\n", getName() ) ); // For now, let's do the async request synchronously request = GetSCSITask ( ); if ( READ_10 ( request, buffer, fMediaBlockSize, ( SCSICmdField4Byte ) startBlock, ( SCSICmdField2Byte ) blockCount ) == true ) { SetApplicationLayerReference( request, clientData ); SendCommand ( request, 0, &IOSCSIReducedBlockCommandsDevice::AsyncReadWriteComplete ); } else { PANIC_NOW ( ( "IOSCSIReducedBlockCommandsDevice::IssueRead malformed command" ) ); } return status; } // Perform the Synchronous Write Request IOReturn IOSCSIReducedBlockCommandsDevice::IssueWrite ( IOMemoryDescriptor * buffer, UInt64 startBlock, UInt64 blockCount ) { SCSIServiceResponse serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE; SCSITaskIdentifier request; IOReturn status = kIOReturnError; STATUS_LOG ( ( "%s: syncWrite Attempted\n", getName ( ) ) ); request = GetSCSITask ( ); if ( WRITE_10 ( request, buffer, fMediaBlockSize, 0, ( SCSICmdField4Byte ) startBlock, ( SCSICmdField2Byte ) blockCount ) == true ) { // The command was successfully built, now send it serviceResponse = SendCommand ( request, 0 ); } else { PANIC_NOW(( "IOSCSIReducedBlockCommandsDevice::IssueWrite malformed command" )); } if ( ( serviceResponse == kSCSIServiceResponse_TASK_COMPLETE ) && ( GetTaskStatus ( request ) == kSCSITaskStatus_GOOD ) ) { status = kIOReturnSuccess; } ReleaseSCSITask ( request ); return status; } // Perform the Asynchronous Write Request IOReturn IOSCSIReducedBlockCommandsDevice::IssueWrite ( IOMemoryDescriptor * buffer, UInt64 startBlock, UInt64 blockCount, void * clientData ) { IOReturn status = kIOReturnSuccess; SCSITaskIdentifier request; STATUS_LOG ( ( "%s: asyncWrite Attempted\n", getName() ) ); request = GetSCSITask ( ); if ( WRITE_10 ( request, buffer, fMediaBlockSize, 0, ( SCSICmdField4Byte ) startBlock, ( SCSICmdField2Byte ) blockCount ) == true ) { SetApplicationLayerReference( request, clientData ); SendCommand ( request, 0, &IOSCSIReducedBlockCommandsDevice::AsyncReadWriteComplete ); } else { PANIC_NOW(( "IOSCSIReducedBlockCommandsDevice::IssueWrite malformed command" )); } return status; } IOReturn IOSCSIReducedBlockCommandsDevice::SyncReadWrite ( IOMemoryDescriptor * buffer, UInt64 startBlock, UInt64 blockCount ) { IODirection direction; IOReturn status; direction = buffer->getDirection ( ); if ( direction == kIODirectionIn ) { status = IssueRead ( buffer, startBlock, blockCount ); } else if ( direction == kIODirectionOut ) { status = IssueWrite ( buffer, startBlock, blockCount ); } else { ERROR_LOG ( ( "%s: SyncReadWrite bad direction argument\n", getName ( ) ) ); status = kIOReturnBadArgument; } return status; } IOReturn IOSCSIReducedBlockCommandsDevice::AsyncReadWrite ( IOMemoryDescriptor * buffer, UInt64 startBlock, UInt64 blockCount, void * clientData ) { IODirection direction; IOReturn status; direction = buffer->getDirection ( ); if ( direction == kIODirectionIn ) { IssueRead ( buffer, startBlock, blockCount, clientData ); status = kIOReturnSuccess; } else if ( direction == kIODirectionOut ) { IssueWrite ( buffer, startBlock, blockCount, clientData ); status = kIOReturnSuccess; } else { ERROR_LOG ( ( "%s: AsyncReadWrite bad direction argument\n", getName ( ) ) ); status = kIOReturnBadArgument; } return status; } IOReturn IOSCSIReducedBlockCommandsDevice::EjectTheMedia ( void ) { SCSIServiceResponse serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE; SCSITaskIdentifier request; STATUS_LOG ( ( "%s::%s called\n", getName ( ), __FUNCTION__ ) ); request = GetSCSITask ( ); if ( fMediaIsRemovable == false ) { if ( SYNCHRONIZE_CACHE( request ) == true ) { // The command was successfully built, now send it serviceResponse = SendCommand ( request, 0 ); } else { PANIC_NOW(( "IOSCSIReducedBlockCommandsDevice::EjectTheMedia malformed command" )); } ReleaseSCSITask ( request ); return kIOReturnSuccess; } if ( PREVENT_ALLOW_MEDIUM_REMOVAL ( request, 0 ) == true ) { // The command was successfully built, now send it serviceResponse = SendCommand ( request, 0 ); } else { PANIC_NOW(( "IOSCSIReducedBlockCommandsDevice::EjectTheMedia malformed command" )); } if ( START_STOP_UNIT ( request, 0, 0, 1, 0 ) == true ) { // The command was successfully built, now send it serviceResponse = SendCommand ( request, 0 ); } else { PANIC_NOW(( "IOSCSIReducedBlockCommandsDevice::EjectTheMedia malformed command" )); } ReleaseSCSITask ( request ); ResetMediaCharacteristics ( ); fMediaIsWriteProtected = true; EnablePolling ( ); return kIOReturnSuccess; } IOReturn IOSCSIReducedBlockCommandsDevice::FormatMedia ( UInt64 byteCapacity ) { IOReturn status = kIOReturnUnsupported; STATUS_LOG ( ( "%s::%s called\n", getName ( ), __FUNCTION__ ) ); return status; } UInt32 IOSCSIReducedBlockCommandsDevice::GetFormatCapacities ( UInt64 * capacities, UInt32 capacitiesMaxCount ) const { STATUS_LOG ( ( "%s::%s called\n", getName ( ), __FUNCTION__ ) ); return 0; } IOReturn IOSCSIReducedBlockCommandsDevice::LockUnlockMedia ( bool doLock ) { return kIOReturnSuccess; } IOReturn IOSCSIReducedBlockCommandsDevice::SynchronizeCache ( void ) { SCSIServiceResponse serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE; SCSITaskIdentifier request; IOReturn status = kIOReturnError; STATUS_LOG ( ( "%s::%s called\n", getName ( ), __FUNCTION__ ) ); request = GetSCSITask ( ); if ( SYNCHRONIZE_CACHE ( request ) == true ) { // The command was successfully built, now send it serviceResponse = SendCommand ( request, 0 ); } else { PANIC_NOW(( "IOSCSIReducedBlockCommandsDevice::SynchronizeCache malformed command" )); } if ( ( serviceResponse == kSCSIServiceResponse_TASK_COMPLETE ) && ( GetTaskStatus ( request ) == kSCSITaskStatus_GOOD ) ) { status = kIOReturnSuccess; } ReleaseSCSITask ( request ); return status; } IOReturn IOSCSIReducedBlockCommandsDevice::ReportBlockSize ( UInt64 * blockSize ) { STATUS_LOG ( ( "%s::%s ReportBlockSize blockSize = %ld\n", getName ( ), __FUNCTION__, ( UInt32 ) fMediaBlockSize ) ); *blockSize = fMediaBlockSize; return kIOReturnSuccess; } IOReturn IOSCSIReducedBlockCommandsDevice::ReportEjectability ( bool * isEjectable ) { STATUS_LOG ( ( "%s::%s ReportEjectability mediaIsRemovable = %d\n", getName ( ), __FUNCTION__, fMediaIsRemovable ) ); *isEjectable = fMediaIsRemovable; return kIOReturnSuccess; } IOReturn IOSCSIReducedBlockCommandsDevice::ReportLockability ( bool * isLockable ) { STATUS_LOG ( ( "%s::%s isLockable = %d\n", getName ( ), __FUNCTION__, true ) ); *isLockable = true; return kIOReturnSuccess; } IOReturn IOSCSIReducedBlockCommandsDevice::ReportPollRequirements ( bool * pollIsRequired, bool * pollIsExpensive ) { STATUS_LOG ( ( "%s::%s called \n", getName ( ), __FUNCTION__ ) ); // *pollIsRequired = fMediaIsRemovable; *pollIsRequired = false; *pollIsExpensive = false; return kIOReturnSuccess; } IOReturn IOSCSIReducedBlockCommandsDevice::ReportMaxReadTransfer ( UInt64 blockSize, UInt64 * max ) { STATUS_LOG ( ( "%s::%s called\n", getName ( ), __FUNCTION__ ) ); *max = blockSize * 256; return kIOReturnSuccess; } IOReturn IOSCSIReducedBlockCommandsDevice::ReportMaxValidBlock ( UInt64 * maxBlock ) { STATUS_LOG ( ( "%s::%s maxBlock = %ld\n", getName ( ), __FUNCTION__, fMediaBlockCount - 1 ) ); *maxBlock = fMediaBlockCount - 1; return kIOReturnSuccess; } IOReturn IOSCSIReducedBlockCommandsDevice::ReportMaxWriteTransfer ( UInt64 blockSize, UInt64 * max ) { STATUS_LOG ( ( "%s::%s called.\n", getName ( ), __FUNCTION__ ) ); return ( ReportMaxReadTransfer ( blockSize, max ) ); } IOReturn IOSCSIReducedBlockCommandsDevice::ReportMediaState ( bool * mediaPresent, bool * changed ) { STATUS_LOG ( ( "%s::%s called.\n", getName ( ), __FUNCTION__ ) ); *mediaPresent = fMediaPresent; *changed = fMediaChanged; //´´´ HACK - Make sure that the next time they call ReportMediaState, // we don't tell them the media changed, else we'll panic. if ( fMediaChanged ) { fMediaChanged = !fMediaChanged; } return kIOReturnSuccess; } IOReturn IOSCSIReducedBlockCommandsDevice::ReportRemovability ( bool * isRemovable ) { STATUS_LOG ( ( "%s::%s isRemovable = %d.\n", getName ( ), __FUNCTION__, fMediaIsRemovable ) ); *isRemovable = fMediaIsRemovable; return kIOReturnSuccess; } IOReturn IOSCSIReducedBlockCommandsDevice::ReportWriteProtection ( bool * isWriteProtected ) { STATUS_LOG ( ( "%s::%s isWriteProtected = %d.\n", getName ( ), __FUNCTION__, fMediaIsWriteProtected ) ); *isWriteProtected = fMediaIsWriteProtected; return kIOReturnSuccess; } void IOSCSIReducedBlockCommandsDevice::sPollForMedia ( void * pdtDriver, void * refCon ) { IOSCSIReducedBlockCommandsDevice * driver; driver = ( IOSCSIReducedBlockCommandsDevice * ) pdtDriver; driver->PollForMedia ( ); if ( !driver->fMediaPresent ) { // schedule the poller again since we didn't find media driver->EnablePolling ( ); } // drop the retain associated with this poll driver->release ( ); } #pragma mark - #pragma mark Reduced Block Commands Builders bool IOSCSIReducedBlockCommandsDevice::FORMAT_UNIT( SCSITaskIdentifier request, SCSICmdField1Bit IMMED, SCSICmdField1Bit PROGRESS, SCSICmdField1Bit PERCENT_TIME, SCSICmdField1Bit INCREMENT ) { SCSITask * scsiRequest; STATUS_LOG ( ( "%s::%s called\n", getName(), __FUNCTION__ ) ); scsiRequest = OSDynamicCast( SCSITask, request ); if ( scsiRequest->ResetForNewTask() == false ) { ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) ); return false; } return GetSCSIReducedBlockCommandObject()->FORMAT_UNIT( scsiRequest, IMMED, PROGRESS, PERCENT_TIME, INCREMENT ); } bool IOSCSIReducedBlockCommandsDevice::INQUIRY( SCSITaskIdentifier request, IOMemoryDescriptor * dataBuffer, SCSICmdField1Bit CMDDT, SCSICmdField1Bit EVPD, SCSICmdField1Byte PAGE_OR_OPERATION_CODE, SCSICmdField1Byte ALLOCATION_LENGTH ) { SCSITask * scsiRequest; STATUS_LOG ( ( "%s::%s called\n", getName(), __FUNCTION__ ) ); scsiRequest = OSDynamicCast( SCSITask, request ); if ( scsiRequest->ResetForNewTask() == false ) { ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) ); return false; } return GetSCSIPrimaryCommandObject()->INQUIRY( scsiRequest, dataBuffer, CMDDT, EVPD, PAGE_OR_OPERATION_CODE, ALLOCATION_LENGTH, 0x00 ); } bool IOSCSIReducedBlockCommandsDevice::MODE_SELECT_6( SCSITaskIdentifier request, IOMemoryDescriptor * dataBuffer, SCSICmdField1Bit PF, SCSICmdField1Bit SP, SCSICmdField1Byte PARAMETER_LIST_LENGTH ) { SCSITask * scsiRequest; STATUS_LOG ( ( "%s::%s called\n", getName(), __FUNCTION__ ) ); scsiRequest = OSDynamicCast( SCSITask, request ); if ( scsiRequest->ResetForNewTask() == false ) { ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) ); return false; } return GetSCSIPrimaryCommandObject()->MODE_SELECT_6( scsiRequest, dataBuffer, PF, SP, PARAMETER_LIST_LENGTH, 0x00 ); } bool IOSCSIReducedBlockCommandsDevice::MODE_SENSE_6( SCSITaskIdentifier request, IOMemoryDescriptor * dataBuffer, SCSICmdField1Bit DBD, SCSICmdField2Bit PC, SCSICmdField6Bit PAGE_CODE, SCSICmdField1Byte ALLOCATION_LENGTH ) { SCSITask * scsiRequest; STATUS_LOG ( ( "%s::%s called\n", getName(), __FUNCTION__ ) ); scsiRequest = OSDynamicCast( SCSITask, request ); if ( scsiRequest->ResetForNewTask() == false ) { ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) ); return false; } return GetSCSIPrimaryCommandObject()->MODE_SENSE_6( scsiRequest, dataBuffer, DBD, PC, PAGE_CODE, ALLOCATION_LENGTH, 0x00 ); } bool IOSCSIReducedBlockCommandsDevice::PERSISTENT_RESERVE_IN( SCSITaskIdentifier request, IOMemoryDescriptor * dataBuffer, SCSICmdField5Bit SERVICE_ACTION, SCSICmdField2Byte ALLOCATION_LENGTH ) { SCSITask * scsiRequest; STATUS_LOG ( ( "%s::%s called\n", getName(), __FUNCTION__ ) ); scsiRequest = OSDynamicCast( SCSITask, request ); if ( scsiRequest->ResetForNewTask() == false ) { ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) ); return false; } return GetSCSIPrimaryCommandObject()->PERSISTENT_RESERVE_IN( scsiRequest, dataBuffer, SERVICE_ACTION, ALLOCATION_LENGTH, 0x00 ); } bool IOSCSIReducedBlockCommandsDevice::PERSISTENT_RESERVE_OUT ( SCSITaskIdentifier request, IOMemoryDescriptor * dataBuffer, SCSICmdField5Bit SERVICE_ACTION, SCSICmdField4Bit SCOPE, SCSICmdField4Bit TYPE ) { SCSITask * scsiRequest; STATUS_LOG ( ( "%s::%s called\n", getName(), __FUNCTION__ ) ); scsiRequest = OSDynamicCast( SCSITask, request ); if ( scsiRequest->ResetForNewTask() == false ) { ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) ); return false; } return GetSCSIPrimaryCommandObject()->PERSISTENT_RESERVE_OUT( scsiRequest, dataBuffer, SERVICE_ACTION, SCOPE, TYPE, 0x00 ); } bool IOSCSIReducedBlockCommandsDevice::PREVENT_ALLOW_MEDIUM_REMOVAL( SCSITaskIdentifier request, SCSICmdField2Bit PREVENT ) { SCSITask * scsiRequest; STATUS_LOG ( ( "%s::%s called\n", getName(), __FUNCTION__ ) ); scsiRequest = OSDynamicCast( SCSITask, request ); if ( scsiRequest->ResetForNewTask() == false ) { ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) ); return false; } return GetSCSIPrimaryCommandObject()->PREVENT_ALLOW_MEDIUM_REMOVAL( scsiRequest, PREVENT, 0x00 ); } bool IOSCSIReducedBlockCommandsDevice::READ_10( SCSITaskIdentifier request, IOMemoryDescriptor * dataBuffer, UInt32 blockSize, SCSICmdField4Byte LOGICAL_BLOCK_ADDRESS, SCSICmdField2Byte TRANSFER_LENGTH ) { SCSITask * scsiRequest; STATUS_LOG ( ( "%s::%s called\n", getName(), __FUNCTION__ ) ); scsiRequest = OSDynamicCast( SCSITask, request ); if ( scsiRequest->ResetForNewTask() == false ) { ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) ); return false; } return GetSCSIReducedBlockCommandObject()->READ_10( scsiRequest, dataBuffer, blockSize, LOGICAL_BLOCK_ADDRESS, TRANSFER_LENGTH ); } bool IOSCSIReducedBlockCommandsDevice::READ_CAPACITY( SCSITaskIdentifier request, IOMemoryDescriptor * dataBuffer ) { SCSITask * scsiRequest; STATUS_LOG ( ( "%s::%s called\n", getName(), __FUNCTION__ ) ); scsiRequest = OSDynamicCast( SCSITask, request ); if ( scsiRequest->ResetForNewTask() == false ) { ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) ); return false; } return GetSCSIReducedBlockCommandObject()->READ_CAPACITY( scsiRequest, dataBuffer ); } bool IOSCSIReducedBlockCommandsDevice::RELEASE_6( SCSITaskIdentifier request ) { SCSITask * scsiRequest; STATUS_LOG ( ( "%s::%s called\n", getName(), __FUNCTION__ ) ); scsiRequest = OSDynamicCast( SCSITask, request ); if ( scsiRequest->ResetForNewTask() == false ) { ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) ); return false; } return GetSCSIPrimaryCommandObject()->RELEASE_6( scsiRequest, 0x00 ); } bool IOSCSIReducedBlockCommandsDevice::REQUEST_SENSE( SCSITaskIdentifier request, IOMemoryDescriptor * dataBuffer, SCSICmdField1Byte ALLOCATION_LENGTH ) { SCSITask * scsiRequest; STATUS_LOG ( ( "%s::%s called\n", getName(), __FUNCTION__ ) ); scsiRequest = OSDynamicCast( SCSITask, request ); if ( scsiRequest->ResetForNewTask() == false ) { ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) ); return false; } return GetSCSIPrimaryCommandObject()->REQUEST_SENSE( scsiRequest, dataBuffer, ALLOCATION_LENGTH, 0x00 ); } bool IOSCSIReducedBlockCommandsDevice::RESERVE_6( SCSITaskIdentifier request ) { SCSITask * scsiRequest; STATUS_LOG ( ( "%s::%s called\n", getName(), __FUNCTION__ ) ); scsiRequest = OSDynamicCast( SCSITask, request ); if ( scsiRequest->ResetForNewTask() == false ) { ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) ); return false; } return GetSCSIPrimaryCommandObject()->RESERVE_6( scsiRequest, 0x00 ); } bool IOSCSIReducedBlockCommandsDevice::START_STOP_UNIT( SCSITaskIdentifier request, SCSICmdField1Bit IMMED, SCSICmdField4Bit POWER_CONDITIONS, SCSICmdField1Bit LOEJ, SCSICmdField1Bit START ) { SCSITask * scsiRequest; STATUS_LOG ( ( "%s::%s called\n", getName(), __FUNCTION__ ) ); scsiRequest = OSDynamicCast( SCSITask, request ); if ( scsiRequest->ResetForNewTask() == false ) { ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) ); return false; } return GetSCSIReducedBlockCommandObject()->START_STOP_UNIT( scsiRequest, IMMED, POWER_CONDITIONS, LOEJ, START ); } bool IOSCSIReducedBlockCommandsDevice::SYNCHRONIZE_CACHE( SCSITaskIdentifier request ) { SCSITask * scsiRequest; STATUS_LOG ( ( "%s::%s called\n", getName(), __FUNCTION__ ) ); scsiRequest = OSDynamicCast( SCSITask, request ); if ( scsiRequest->ResetForNewTask() == false ) { ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) ); return false; } return GetSCSIReducedBlockCommandObject()->SYNCHRONIZE_CACHE( scsiRequest ); } bool IOSCSIReducedBlockCommandsDevice::TEST_UNIT_READY( SCSITaskIdentifier request ) { SCSITask * scsiRequest; STATUS_LOG ( ( "%s::%s called\n", getName(), __FUNCTION__ ) ); scsiRequest = OSDynamicCast( SCSITask, request ); if ( scsiRequest->ResetForNewTask() == false ) { ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) ); return false; } return GetSCSIPrimaryCommandObject()->TEST_UNIT_READY( scsiRequest, 0x00 ); } bool IOSCSIReducedBlockCommandsDevice::VERIFY( SCSITaskIdentifier request, SCSICmdField4Byte LOGICAL_BLOCK_ADDRESS, SCSICmdField2Byte VERIFICATION_LENGTH ) { SCSITask * scsiRequest; STATUS_LOG ( ( "%s::%s called\n", getName(), __FUNCTION__ ) ); scsiRequest = OSDynamicCast( SCSITask, request ); if ( scsiRequest->ResetForNewTask() == false ) { ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) ); return false; } return GetSCSIReducedBlockCommandObject()->VERIFY( scsiRequest, LOGICAL_BLOCK_ADDRESS, VERIFICATION_LENGTH ); } bool IOSCSIReducedBlockCommandsDevice::WRITE_10( SCSITaskIdentifier request, IOMemoryDescriptor * dataBuffer, UInt32 blockSize, SCSICmdField1Bit FUA, SCSICmdField4Byte LOGICAL_BLOCK_ADDRESS, SCSICmdField2Byte TRANSFER_LENGTH ) { SCSITask * scsiRequest; STATUS_LOG ( ( "%s::%s called\n", getName(), __FUNCTION__ ) ); scsiRequest = OSDynamicCast( SCSITask, request ); if ( scsiRequest->ResetForNewTask() == false ) { ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) ); return false; } return GetSCSIReducedBlockCommandObject()->WRITE_10( scsiRequest, dataBuffer, blockSize, FUA, LOGICAL_BLOCK_ADDRESS, TRANSFER_LENGTH ); } bool IOSCSIReducedBlockCommandsDevice::WRITE_BUFFER( SCSITaskIdentifier request, IOMemoryDescriptor * dataBuffer, SCSICmdField4Bit MODE, SCSICmdField1Byte BUFFER_ID, SCSICmdField3Byte BUFFER_OFFSET, SCSICmdField3Byte PARAMETER_LIST_LENGTH ) { SCSITask * scsiRequest; STATUS_LOG ( ( "%s::%s called\n", getName(), __FUNCTION__ ) ); scsiRequest = OSDynamicCast( SCSITask, request ); if ( scsiRequest->ResetForNewTask() == false ) { ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) ); return false; } return GetSCSIPrimaryCommandObject()->WRITE_BUFFER( scsiRequest, dataBuffer, MODE, BUFFER_ID, BUFFER_OFFSET, PARAMETER_LIST_LENGTH, 0x00 ); } OSMetaClassDefineReservedUsed( IOSCSIReducedBlockCommandsDevice, 1 ); /* PowerDownHandler */ // Space reserved for future expansion. OSMetaClassDefineReservedUnused( IOSCSIReducedBlockCommandsDevice, 2 ); OSMetaClassDefineReservedUnused( IOSCSIReducedBlockCommandsDevice, 3 ); OSMetaClassDefineReservedUnused( IOSCSIReducedBlockCommandsDevice, 4 ); OSMetaClassDefineReservedUnused( IOSCSIReducedBlockCommandsDevice, 5 ); OSMetaClassDefineReservedUnused( IOSCSIReducedBlockCommandsDevice, 6 ); OSMetaClassDefineReservedUnused( IOSCSIReducedBlockCommandsDevice, 7 ); OSMetaClassDefineReservedUnused( IOSCSIReducedBlockCommandsDevice, 8 ); OSMetaClassDefineReservedUnused( IOSCSIReducedBlockCommandsDevice, 9 ); OSMetaClassDefineReservedUnused( IOSCSIReducedBlockCommandsDevice, 10 ); OSMetaClassDefineReservedUnused( IOSCSIReducedBlockCommandsDevice, 11 ); OSMetaClassDefineReservedUnused( IOSCSIReducedBlockCommandsDevice, 12 ); OSMetaClassDefineReservedUnused( IOSCSIReducedBlockCommandsDevice, 13 ); OSMetaClassDefineReservedUnused( IOSCSIReducedBlockCommandsDevice, 14 ); OSMetaClassDefineReservedUnused( IOSCSIReducedBlockCommandsDevice, 15 ); OSMetaClassDefineReservedUnused( IOSCSIReducedBlockCommandsDevice, 16 );