sl@0: // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // sl@0: sl@0: /** sl@0: @file sl@0: @internalTechnology sl@0: */ sl@0: sl@0: #include sl@0: sl@0: #include "debug.h" sl@0: #include "msdebug.h" sl@0: #include "msctypes.h" sl@0: #include "shared.h" sl@0: #include "msgservice.h" sl@0: sl@0: #include "mscutils.h" sl@0: sl@0: #include "mtransport.h" sl@0: #include "mprotocol.h" sl@0: #include "tscsiclientreq.h" sl@0: #include "tscsiprimarycmds.h" sl@0: #include "tscsiblockcmds.h" sl@0: sl@0: #include "mblocktransferprotocol.h" sl@0: #include "tblocktransfer.h" sl@0: sl@0: #include "tsbcclientinterface.h" sl@0: #include "tspcclientinterface.h" sl@0: #include "cmassstoragefsm.h" sl@0: #include "cscsiprotocol.h" sl@0: sl@0: #include "usbmshostpanic.h" sl@0: sl@0: sl@0: sl@0: /** sl@0: Create the CScsiProtocol object. sl@0: sl@0: @param aLun The LUN for the device represented by this object sl@0: @param aTransport The transport interface sl@0: @param aStatusPollingInterval The polling interval sl@0: @return CScsiProtocol* A reference to the sl@0: */ sl@0: CScsiProtocol* CScsiProtocol::NewL(TLun aLun, MTransport& aTransport) sl@0: { sl@0: __MSFNSLOG sl@0: CScsiProtocol* r = new (ELeave) CScsiProtocol(aTransport); sl@0: sl@0: CleanupStack::PushL(r); sl@0: r->ConstructL(aLun); sl@0: CleanupStack::Pop(); sl@0: return r; sl@0: } sl@0: sl@0: void CScsiProtocol::ConstructL(TLun aLun) sl@0: { sl@0: __MSFNLOG sl@0: iFsm = CMassStorageFsm::NewL(*this); sl@0: iState = EDisconnected; sl@0: sl@0: const TInt blockLength = 0x200; sl@0: sl@0: iHeadbuf.CreateL(blockLength); sl@0: iTailbuf.CreateL(blockLength); sl@0: } sl@0: sl@0: sl@0: CScsiProtocol::CScsiProtocol(MTransport& aTransport) sl@0: : iSpcInterface(aTransport), sl@0: iSbcInterface(NULL) sl@0: { sl@0: __MSFNLOG sl@0: } sl@0: sl@0: sl@0: CScsiProtocol::~CScsiProtocol() sl@0: { sl@0: __MSFNLOG sl@0: delete iFsm; sl@0: iHeadbuf.Close(); sl@0: iTailbuf.Close(); sl@0: delete iSbcInterface; sl@0: } sl@0: sl@0: sl@0: void CScsiProtocol::InitialiseUnitL() sl@0: { sl@0: __MSFNLOG sl@0: sl@0: // A device may take time to mount the media. If the device fails attempt to sl@0: // retry the connection for a number of seconds sl@0: TInt retryCounter = 20; sl@0: do sl@0: { sl@0: retryCounter--; sl@0: iFsm->ConnectLogicalUnitL(); sl@0: iState = iFsm->IsConnected() ? EConnected: EDisconnected; sl@0: sl@0: if (iState == EConnected) sl@0: { sl@0: break; sl@0: } sl@0: User::After(1000 * 200); // 200 mS sl@0: } sl@0: while (retryCounter); sl@0: } sl@0: sl@0: sl@0: void CScsiProtocol::UninitialiseUnitL() sl@0: { sl@0: __MSFNLOG sl@0: iFsm->DisconnectLogicalUnitL(); sl@0: } sl@0: sl@0: TBool CScsiProtocol::IsConnected() sl@0: { sl@0: __MSFNLOG sl@0: return (iState == EConnected)? ETrue : EFalse; sl@0: } sl@0: sl@0: void CScsiProtocol::ReadL(TPos aPos, sl@0: TDes8& aBuf, sl@0: TInt aLength) sl@0: { sl@0: __MSFNLOG sl@0: if(!IsConnected()) sl@0: User::Leave(KErrNotReady); sl@0: iSbcInterface->iBlockTransfer.ReadL(*this, aPos, aLength, aBuf); sl@0: } sl@0: sl@0: sl@0: void CScsiProtocol::BlockReadL(TPos aPos, TDes8& aCopybuf, TInt aLen) sl@0: { sl@0: __MSFNLOG sl@0: __ASSERT_DEBUG(aPos % iSbcInterface->iBlockTransfer.BlockLength() == 0, sl@0: User::Panic(KUsbMsHostPanicCat, EBlockDevice)); sl@0: sl@0: const TInt blockLen = iSbcInterface->iBlockTransfer.BlockLength(); sl@0: TInt len = aLen; sl@0: sl@0: TInt64 lba = aPos / static_cast(blockLen); sl@0: sl@0: if (I64HIGH(lba)) sl@0: { sl@0: User::LeaveIfError(KErrOverflow); sl@0: } sl@0: sl@0: TInt err = iSbcInterface->Read10L(I64LOW(lba), aCopybuf, len); sl@0: if (err) sl@0: { sl@0: __SCSIPRINT1(_L("READ(10) Err=%d"), err); sl@0: DoCheckConditionL(); sl@0: User::LeaveIfError(KErrAbort); sl@0: } sl@0: sl@0: // handle residue sl@0: while (len != aLen) sl@0: { sl@0: __SCSIPRINT2(_L("SCSI Read Residue 0x%x bytes read (0x%x)"), len, aLen); sl@0: __SCSIPRINT2(_L("Pos=0x%lx Len=0x%x"), aPos, aLen); sl@0: sl@0: // read next block sl@0: sl@0: // full blocks read in bytes sl@0: TInt bytesRead = len/blockLen * blockLen; sl@0: aPos += bytesRead; sl@0: aLen -= bytesRead; sl@0: len = aLen; sl@0: sl@0: __SCSIPRINT3(_L("New Pos=0x%lx Len=0x%x (bytes read = %x)"), sl@0: aPos, aLen, bytesRead); sl@0: sl@0: aCopybuf.SetLength(bytesRead); sl@0: sl@0: // read rest of the block sl@0: TInt err = iSbcInterface->Read10L(aPos/blockLen, aCopybuf, len); sl@0: if (err) sl@0: { sl@0: DoCheckConditionL(); sl@0: User::LeaveIfError(KErrAbort); sl@0: } sl@0: } sl@0: } sl@0: sl@0: sl@0: void CScsiProtocol::WriteL(TPos aPosition, sl@0: TDesC8& aBuf, sl@0: TInt aLength) sl@0: { sl@0: __MSFNLOG sl@0: if(!IsConnected()) sl@0: User::Leave(KErrNotReady); sl@0: iSbcInterface->iBlockTransfer.WriteL(*this, aPosition, aLength, aBuf); sl@0: } sl@0: sl@0: sl@0: void CScsiProtocol::BlockWriteL(TPos aPos, TDesC8& aCopybuf, TUint aOffset, TInt aLen) sl@0: { sl@0: __MSFNLOG sl@0: __ASSERT_DEBUG(aPos % iSbcInterface->iBlockTransfer.BlockLength() == 0, sl@0: User::Panic(KUsbMsHostPanicCat, EBlockDevice)); sl@0: const TInt blockLen = iSbcInterface->iBlockTransfer.BlockLength(); sl@0: TInt len = aLen; sl@0: TInt err = iSbcInterface->Write10L(aPos/blockLen, aCopybuf, aOffset, len); sl@0: if (err) sl@0: { sl@0: DoCheckConditionL(); sl@0: User::LeaveIfError(KErrAbort); sl@0: } sl@0: sl@0: while (len != aLen) sl@0: { sl@0: // handle residue sl@0: __SCSIPRINT2(_L("SCSI Write Residue 0x%x bytes read (0x%x)"), len, aLen); sl@0: __SCSIPRINT2(_L("Pos=0x%lx Len=0x%x"), aPos, aLen); sl@0: sl@0: // write next block sl@0: sl@0: // full blocks written in bytes sl@0: TInt bytesWritten = len/blockLen * blockLen; sl@0: aPos += bytesWritten; sl@0: aLen -= bytesWritten; sl@0: len = aLen; sl@0: __SCSIPRINT2(_L("New Pos=0x%lx Len=0x%x"), aPos, aLen); sl@0: sl@0: TPtrC8 buf = aCopybuf.Mid(bytesWritten); sl@0: sl@0: // write rest of the block sl@0: TInt err = iSbcInterface->Write10L(aPos/blockLen, buf, aOffset, len); sl@0: if (err) sl@0: { sl@0: DoCheckConditionL(); sl@0: User::LeaveIfError(KErrAbort); sl@0: } sl@0: } sl@0: } sl@0: sl@0: sl@0: void CScsiProtocol::GetCapacityL(TCapsInfo& aCapsInfo) sl@0: { sl@0: __MSFNLOG sl@0: if (!IsConnected()) sl@0: { sl@0: DoScsiReadyCheckEventL(); sl@0: } sl@0: sl@0: TLba lastLba; sl@0: TUint32 blockLength; sl@0: sl@0: // Retry ReadCapacity10L if stalled sl@0: TInt stallCounter = 4; sl@0: TInt err = KErrNone; sl@0: do sl@0: { sl@0: err = iSbcInterface->ReadCapacity10L(lastLba, blockLength); sl@0: } while (err == KErrCommandStalled && stallCounter-- > 0); sl@0: sl@0: sl@0: if (err) sl@0: { sl@0: if (err == KErrCommandFailed) sl@0: { sl@0: // Clear sense error sl@0: DoCheckConditionL(); sl@0: } sl@0: User::LeaveIfError(KErrAbort); sl@0: } sl@0: sl@0: // update iWriteProtect sl@0: err = MsModeSense10L(); sl@0: if (err) sl@0: { sl@0: if (err == KErrCommandFailed) sl@0: { sl@0: // Clear sense error sl@0: DoCheckConditionL(); sl@0: } sl@0: sl@0: err = MsModeSense6L(); sl@0: if (err == KErrCommandFailed) sl@0: { sl@0: // Clear sense error sl@0: DoCheckConditionL(); sl@0: } sl@0: } sl@0: sl@0: aCapsInfo.iNumberOfBlocks = lastLba + 1; sl@0: aCapsInfo.iBlockLength = blockLength; sl@0: aCapsInfo.iWriteProtect = iWriteProtect; sl@0: sl@0: __SCSIPRINT3(_L("numBlock = x%x , blockLength = %x wp = %d"), sl@0: lastLba + 1, blockLength, iWriteProtect); sl@0: } sl@0: sl@0: sl@0: /** sl@0: Perform SCSI INQUIRY command. The function leaves if the device response is not sl@0: compliant with the protocol standard. sl@0: sl@0: @return TInt KErrNone if successful otherwise KErrCommandFailed to indicate a sl@0: device status error sl@0: */ sl@0: TInt CScsiProtocol::MsInquiryL() sl@0: { sl@0: __MSFNLOG sl@0: ResetSbc(); sl@0: sl@0: /** sl@0: INQUIRY sl@0: */ sl@0: sl@0: /** sl@0: SPC states sl@0: - the INQUIRY data should be returned even though the device server is not sl@0: ready for other commands. sl@0: sl@0: - If the standard INQUIRY data changes for any reason, the device server sl@0: shall generate a unit attention condition sl@0: */ sl@0: TPeripheralInfo info; sl@0: TInt err = iSpcInterface.InquiryL(info); sl@0: if (err) sl@0: { sl@0: // KErrCommandFailed sl@0: return err; sl@0: } sl@0: sl@0: // print reponse sl@0: __TESTREPORT1(_L("RMB = %d"), info.iRemovable); sl@0: __TESTREPORT2(_L("PERIPHERAL DEVICE TYPE = %d PQ = %d"), sl@0: info.iPeripheralDeviceType, sl@0: info.iPeripheralQualifier); sl@0: __TESTREPORT1(_L("VERSION = %d"), info.iVersion); sl@0: __TESTREPORT1(_L("RESPONSE DATA FORMAT = %d"), info.iResponseDataFormat); sl@0: __TESTREPORT3(_L("VENDOR ID %S PRODUCT ID %S REV %S"), sl@0: &info.iIdentification.iVendorId, sl@0: &info.iIdentification.iProductId, sl@0: &info.iIdentification.iProductRev); sl@0: sl@0: if (info.iPeripheralQualifier != 0 && info.iPeripheralQualifier != 1) sl@0: { sl@0: __HOSTPRINT(_L("Peripheral Qualifier[Unknown device type]\n")) sl@0: return KErrNotSupported; sl@0: } sl@0: sl@0: if (info.iPeripheralDeviceType != 0) sl@0: { sl@0: __HOSTPRINT(_L("Peripheral Device Type[Unsupported device type]\n")) sl@0: return KErrNotSupported; sl@0: } sl@0: sl@0: iRemovableMedia = info.iRemovable; sl@0: sl@0: // SCSI Block device sl@0: iSbcInterface = new (ELeave) TSbcClientInterface(iSpcInterface.Transport()); sl@0: iSbcInterface->InitBuffers(&iHeadbuf, &iTailbuf); sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Perform SCSI TEST UNIT READY command. The function leaves if the device response sl@0: is not compliant with the protocol standard. sl@0: sl@0: @return TInt KErrNone if successful or otherwise KErrCommandFailed to indicate a sl@0: device status error sl@0: */ sl@0: TInt CScsiProtocol::MsTestUnitReadyL() sl@0: { sl@0: __MSFNLOG sl@0: /* TestUnitReady */ sl@0: return iSpcInterface.TestUnitReadyL(); sl@0: } sl@0: sl@0: sl@0: /** sl@0: Perform SCSI READ CAPACITY (10) command. The function leaves if the device sl@0: response is not compliant with the protocol standard. sl@0: sl@0: Before a block device can be read or written the media's capacity (LAST LBA and sl@0: BLOCK SIZE) must be obtained. This function is used to initialise TBlockTransfer sl@0: with the capacity parameters via TSbcInterface::ReadCapcaityL(). sl@0: sl@0: @return TInt KErrNone if successful, KErrCommandFailed to indicate a sl@0: device status error, KErrCommandStalled to indicate a device stall sl@0: */ sl@0: TInt CScsiProtocol::MsReadCapacityL() sl@0: { sl@0: __MSFNLOG sl@0: // READ CAPACITY sl@0: TUint32 blockSize; sl@0: TUint32 lastLba; sl@0: TInt err = iSbcInterface->ReadCapacity10L(lastLba, blockSize); sl@0: sl@0: __TESTREPORT2(_L("CAPACITY: Block Size=0x%x Last LBA=0x%x"), blockSize, lastLba); sl@0: return err; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Perform MODE SENSE (10) command. The function leaves if the device response is sl@0: not compliant with the protocol standard. sl@0: sl@0: @return TInt KErrNone if successful, KErrCommandFailed to indicate a sl@0: device status error, KErrCommandStalled to indicate a device stall sl@0: */ sl@0: TInt CScsiProtocol::MsModeSense10L() sl@0: { sl@0: __MSFNLOG sl@0: TBool writeProtected; sl@0: TInt err = iSbcInterface->ModeSense10L(TSbcClientInterface::EReturnAllModePages, writeProtected); sl@0: sl@0: if (!err) sl@0: { sl@0: iWriteProtect = writeProtected; sl@0: } sl@0: return err; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Perform SCSI MODE SENSE (6) command. The function leaves if the device response sl@0: is not compliant with the protocol standard. sl@0: sl@0: @return TInt KErrNone if successful, KErrCommandFailed to indicate a sl@0: device status error, KErrCommandStalled to indicate a device stall sl@0: */ sl@0: TInt CScsiProtocol::MsModeSense6L() sl@0: { sl@0: __MSFNLOG sl@0: TBool writeProtected; sl@0: TInt err = iSbcInterface->ModeSense6L(TSbcClientInterface::EReturnAllModePages, writeProtected); sl@0: sl@0: if (!err) sl@0: { sl@0: iWriteProtect = writeProtected; sl@0: } sl@0: return err; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Perform SCSI START STOP UNIT command. The function leaves if the device response sl@0: is not compliant with the protocol standard. sl@0: sl@0: @return TInt KErrNone if successful otherwise KErrCommandFailed to indicate a sl@0: device status error sl@0: */ sl@0: TInt CScsiProtocol::MsStartStopUnitL(TBool aStart) sl@0: { sl@0: __MSFNLOG sl@0: return iSbcInterface->StartStopUnitL(aStart); sl@0: } sl@0: sl@0: sl@0: /** sl@0: Perform SCSI PREVENT ALLOW MEDIA REMOVAL command. The function leaves if the sl@0: device response is not compliant with the protocol standard. sl@0: sl@0: @return TInt KErrNone if successful otherwise KErrCommandFailed to indicate a sl@0: device status error sl@0: */ sl@0: TInt CScsiProtocol::MsPreventAllowMediaRemovalL(TBool aPrevent) sl@0: { sl@0: __MSFNLOG sl@0: return iSpcInterface.PreventAllowMediumRemovalL(aPrevent); sl@0: } sl@0: sl@0: sl@0: void CScsiProtocol::DoCheckConditionL() sl@0: { sl@0: __MSFNLOG sl@0: User::LeaveIfError(MsRequestSenseL()); sl@0: sl@0: // Check if init is needed sl@0: if (iSenseInfo.iSenseCode == TSenseInfo::ENotReady && sl@0: iSenseInfo.iAdditional == TSenseInfo::EAscLogicalUnitNotReady && sl@0: iSenseInfo.iQualifier == TSenseInfo::EAscqInitializingCommandRequired) sl@0: { sl@0: // start unit sl@0: TInt err = iSbcInterface->StartStopUnitL(ETrue); sl@0: sl@0: if (err) sl@0: { sl@0: User::LeaveIfError(MsRequestSenseL()); sl@0: } sl@0: sl@0: } sl@0: sl@0: TInt r = GetSystemWideSenseError(iSenseInfo); sl@0: sl@0: if (((r == KErrNotReady) && (iState == EConnected)) || sl@0: r == KErrDisconnected) sl@0: { sl@0: CompleteNotifyChangeL(); sl@0: } sl@0: } sl@0: sl@0: sl@0: /** sl@0: Map SCSI sense error to a system wide error code sl@0: KErrNotReady could happen due to any of the following reasons: sl@0: 1. Lun is in the process of becoming ready sl@0: 2. Initialising command is required sl@0: 3. Lun is not ready to process the command - meaning it is still handling sl@0: the previous command sl@0: sl@0: KErrUnknown could happen due to any of the following reasons: sl@0: 1. Mass storage device does not respond to the selected logical unit, other sl@0: than the locial unit not ready scenario 2. The command sent was not sl@0: recognized or contains a invalid code 3. Invialid field in the command block sl@0: 4. The requested logical unit is not supported sl@0: 5. The mass storage device cnosists of insufficient resource sl@0: 6. Hardware error sl@0: 7. Blank check sl@0: 8. Vendor specific error sl@0: 9. Any illegal request (we assume the commands sent by MSC should be sl@0: supported by the device, if not then the illegal request is said to be of sl@0: unknown system wide error for Symbian. 10. Miscompare - we do not support sl@0: the compare operation/command so this error should not happen sl@0: sl@0: KErrAccessDenied could happen due to any of the following reasons: sl@0: 1. Data protection error happened sl@0: 2. Media was write protected sl@0: 3. Media was not present sl@0: sl@0: KErrOverflow could happen due to any of the following reasons: sl@0: 1. Data over flow occured sl@0: 2. The requested LBA is out of range sl@0: sl@0: KErrAbort could happen due to any of the following reasons: sl@0: 1. A copy operation is aborted. sl@0: 2. The command is aborted sl@0: sl@0: KErrCorrupt could happen due to any of the following reasons: sl@0: 1. The underlying media was having errors sl@0: sl@0: KErrDisconnected could happen due to any of the following reasons: sl@0: 1. The media was changed/removed - While this error is happening the file sl@0: extension will be notified setting the iChanged flag sl@0: */ sl@0: TInt CScsiProtocol::GetSystemWideSenseError(const TSenseInfo& aSenseInfo) sl@0: { sl@0: __MSFNLOG sl@0: TInt ret = KErrNone; sl@0: TInt additionalError = KErrNone; sl@0: sl@0: switch(aSenseInfo.iSenseCode) sl@0: { sl@0: case TSenseInfo::ENoSense: sl@0: case TSenseInfo::ERecoveredError: sl@0: ret = KErrNone; sl@0: break; sl@0: case TSenseInfo::ENotReady: sl@0: ret = KErrNotReady; sl@0: additionalError = ProcessAsCodes(aSenseInfo); sl@0: if (additionalError != KErrNone) sl@0: { sl@0: ret = additionalError; sl@0: } sl@0: break; sl@0: case TSenseInfo::EMediumError: sl@0: ret = KErrCorrupt; sl@0: additionalError = ProcessAsCodes(aSenseInfo); sl@0: if (additionalError != KErrNone) sl@0: { sl@0: ret = additionalError; sl@0: } sl@0: break; sl@0: case TSenseInfo::EUnitAttention: sl@0: ret = KErrDisconnected; sl@0: break; sl@0: case TSenseInfo::EDataProtection: sl@0: ret = KErrAccessDenied; sl@0: break; sl@0: case TSenseInfo::EIllegalRequest: sl@0: case TSenseInfo::EHardwareError: sl@0: case TSenseInfo::EBlankCheck: sl@0: case TSenseInfo::EVendorSpecific: sl@0: case TSenseInfo::EMisCompare: sl@0: ret = KErrUnknown; sl@0: break; sl@0: case TSenseInfo::ECopyAborted: sl@0: case TSenseInfo::EAbortedCommand: sl@0: ret = KErrAbort; sl@0: break; sl@0: case TSenseInfo::EDataOverflow: sl@0: ret = KErrOverflow; sl@0: break; sl@0: default: sl@0: ret = KErrUnknown; sl@0: break; sl@0: } sl@0: sl@0: return ret; sl@0: } sl@0: sl@0: sl@0: TInt CScsiProtocol::ProcessAsCodes(const TSenseInfo& aSenseInfo) sl@0: { sl@0: __MSFNLOG sl@0: TInt ret = KErrNone; sl@0: sl@0: switch(aSenseInfo.iAdditional) sl@0: { sl@0: case TSenseInfo::EAscLogicalUnitNotReady: sl@0: case TSenseInfo::EMediaNotPresent: sl@0: ret = KErrNotReady; sl@0: break; sl@0: sl@0: case TSenseInfo::ELbaOutOfRange: sl@0: ret = KErrOverflow; sl@0: break; sl@0: sl@0: case TSenseInfo::EWriteProtected: sl@0: ret = KErrAccessDenied; sl@0: break; sl@0: sl@0: case TSenseInfo::ENotReadyToReadyChange: sl@0: ret = KErrNone; sl@0: break; sl@0: sl@0: case TSenseInfo::EAscLogicalUnitDoesNotRespondToSelection: sl@0: case TSenseInfo::EInvalidCmdCode: sl@0: case TSenseInfo::EInvalidFieldInCdb: sl@0: case TSenseInfo::ELuNotSupported: sl@0: case TSenseInfo::EInsufficientRes: sl@0: ret = KErrUnknown; sl@0: break; sl@0: default: sl@0: ret = KErrNone; sl@0: break; sl@0: } sl@0: return ret; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Perform SCSI REQUEST SENSE command. The function leaves if the device response sl@0: is not compliant with the protocol standard. sl@0: sl@0: @return TInt KErrNone if successful otherwise KErrCommandFailed to indicate a sl@0: device status error sl@0: */ sl@0: TInt CScsiProtocol::MsRequestSenseL() sl@0: { sl@0: __MSFNLOG sl@0: return iSpcInterface.RequestSenseL(iSenseInfo) ? KErrCommandFailed : KErrNone; sl@0: } sl@0: sl@0: sl@0: void CScsiProtocol::CreateSbcInterfaceL(TUint32 aBlockLen, TUint32 aLastLba) sl@0: { sl@0: __MSFNLOG sl@0: // SCSI Block device sl@0: ASSERT(iSbcInterface == NULL); sl@0: iSbcInterface = new (ELeave) TSbcClientInterface(iSpcInterface.Transport()); sl@0: iSbcInterface->InitBuffers(&iHeadbuf, &iTailbuf); sl@0: iSbcInterface->SetCapacityL(aBlockLen, aLastLba); sl@0: } sl@0: sl@0: sl@0: void CScsiProtocol::ResetSbc() sl@0: { sl@0: __MSFNLOG sl@0: if (iSbcInterface) sl@0: { sl@0: delete iSbcInterface; sl@0: iSbcInterface = NULL; sl@0: } sl@0: } sl@0: sl@0: sl@0: void CScsiProtocol::NotifyChange(const RMessage2& aMessage) sl@0: { sl@0: __MSFNLOG sl@0: iMediaChangeNotifier.Register(aMessage); sl@0: } sl@0: sl@0: sl@0: void CScsiProtocol::ForceCompleteNotifyChangeL() sl@0: { sl@0: __MSFNLOG sl@0: iMediaChangeNotifier.DoNotifyL(); sl@0: } sl@0: sl@0: sl@0: void CScsiProtocol::CancelChangeNotifierL() sl@0: { sl@0: __MSFNLOG sl@0: iMediaChangeNotifier.DoCancelL(); sl@0: } sl@0: sl@0: sl@0: void CScsiProtocol::SuspendL() sl@0: { sl@0: __MSFNLOG sl@0: if (iFsm->StartStopUnitRequired()) sl@0: { sl@0: iSbcInterface->StartStopUnitL(EFalse); sl@0: } sl@0: } sl@0: sl@0: void CScsiProtocol::ResumeL() sl@0: { sl@0: __MSFNLOG sl@0: if (iFsm->StartStopUnitRequired()) sl@0: { sl@0: iSbcInterface->StartStopUnitL(ETrue); sl@0: } sl@0: } sl@0: sl@0: sl@0: void CScsiProtocol::DoScsiReadyCheckEventL() sl@0: { sl@0: __MSFNLOG sl@0: TInt err = KErrNone; sl@0: sl@0: if(iFsm->IsRemovableMedia() || iState == EDisconnected) sl@0: { sl@0: iFsm->SetStatusCheck(); sl@0: TRAP(err, iFsm->ConnectLogicalUnitL()); sl@0: iFsm->ClearStatusCheck(); sl@0: sl@0: User::LeaveIfError(err); sl@0: err = iFsm->IsConnected() ? KErrNone : KErrNotReady; sl@0: } sl@0: sl@0: if (iState == EConnected) sl@0: { sl@0: if (err != KErrNone) sl@0: { sl@0: iState = EDisconnected; sl@0: __SCSIPRINT(_L("** Disconnected Notification **")); sl@0: iMediaChangeNotifier.DoNotifyL(); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: if (err == KErrNone) sl@0: { sl@0: iState = EConnected; sl@0: __SCSIPRINT(_L("** Connected Notification **")); sl@0: iMediaChangeNotifier.DoNotifyL(); sl@0: } sl@0: } sl@0: } sl@0: sl@0: void CScsiProtocol::CompleteNotifyChangeL() sl@0: { sl@0: __MSFNLOG sl@0: if (!iFsm->IsStatusCheck()) sl@0: { sl@0: if (iState == EConnected) sl@0: { sl@0: iState = EDisconnected; sl@0: iMediaChangeNotifier.DoNotifyL(); sl@0: } sl@0: } sl@0: } sl@0: sl@0: RMediaChangeNotifier::RMediaChangeNotifier() sl@0: : iRegistered(EFalse) sl@0: { sl@0: __MSFNSLOG sl@0: } sl@0: sl@0: sl@0: RMediaChangeNotifier::~RMediaChangeNotifier() sl@0: { sl@0: __MSFNSLOG sl@0: if (iRegistered) sl@0: iNotifier.Complete(KErrDisconnected); sl@0: } sl@0: sl@0: /** sl@0: Initialise notifier to enable media change notfications. sl@0: sl@0: @param aMessage The message to commplete the notification sl@0: */ sl@0: void RMediaChangeNotifier::Register(const RMessage2& aMessage) sl@0: { sl@0: __MSFNLOG sl@0: iRegistered = ETrue; sl@0: iNotifier = aMessage; sl@0: } sl@0: sl@0: sl@0: void RMediaChangeNotifier::DoNotifyL() sl@0: { sl@0: __MSFNLOG sl@0: CompleteNotifierL(KErrNone); sl@0: } sl@0: sl@0: void RMediaChangeNotifier::DoCancelL() sl@0: { sl@0: __MSFNLOG sl@0: CompleteNotifierL(KErrCancel); sl@0: } sl@0: sl@0: void RMediaChangeNotifier::CompleteNotifierL(TInt aReason) sl@0: { sl@0: __MSFNLOG sl@0: if (iRegistered) sl@0: { sl@0: TBool mediaChanged = ETrue; sl@0: TPtrC8 pStatus((TUint8*)&mediaChanged,sizeof(TBool)); sl@0: iNotifier.WriteL(0,pStatus); sl@0: iNotifier.Complete(aReason); sl@0: iRegistered = EFalse; sl@0: } sl@0: }