sl@0: // Copyright (c) 2004-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: #include "scsiprot.h" sl@0: #ifdef MSDC_MULTITHREADED sl@0: #include "rwdrivethread.h" sl@0: #endif // MSDC_MULTITHREADED sl@0: #include "massstoragedebug.h" sl@0: sl@0: // Helper macros sl@0: #define LBA(x) static_cast((x[3] << 24) | (x[4] << 16) | (x[5] << 8) | x[6]) sl@0: #define LEN(x) static_cast((x[8] << 8) | x[9]) sl@0: sl@0: sl@0: LOCAL_D const TUint KDefaultBlockSize = 0x200; //default block size for FAT sl@0: sl@0: LOCAL_D const TUint KUndefinedLun = 0xFFFF; sl@0: sl@0: LOCAL_D const TUint8 KAllPages = 0x3F; sl@0: sl@0: LOCAL_D const TUint8 KChangeableValues = 0x1; sl@0: LOCAL_D const TUint8 KDefaultValues = 0x2; sl@0: sl@0: /** sl@0: Default constructor for TSenseInfo sl@0: */ sl@0: TSenseInfo::TSenseInfo() sl@0: : iSenseCode(ENoSense), sl@0: iAdditional(EAscNull), sl@0: iQualifier(EAscqNull) sl@0: {} sl@0: sl@0: sl@0: /** sl@0: Set sense with no additional info. sl@0: sl@0: @param aSenseCode sense key sl@0: */ sl@0: void TSenseInfo::SetSense(TSenseCode aSenseCode) sl@0: { sl@0: iSenseCode = static_cast(aSenseCode); sl@0: iAdditional = EAscNull; sl@0: iQualifier = EAscqNull; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Set sense with additional info. sl@0: sl@0: @param aSenseCode sense key sl@0: @param aAdditional additional sense code (ASC) sl@0: */ sl@0: void TSenseInfo::SetSense(TSenseCode aSenseCode, TAdditionalCode aAdditional) sl@0: sl@0: { sl@0: iSenseCode = static_cast(aSenseCode); sl@0: iAdditional = static_cast(aAdditional); sl@0: iQualifier = EAscqNull; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Set sense with additional info and qualifier. sl@0: sl@0: @param aSenseCode sense key sl@0: @param aAdditional additional sense code (ASC) sl@0: @param aQualifier additional sense code qualifier (ASCQ) sl@0: */ sl@0: void TSenseInfo::SetSense(TSenseCode aSenseCode, sl@0: TAdditionalCode aAdditional, sl@0: TAdditionalSenseCodeQualifier aQualifier) sl@0: { sl@0: iSenseCode = static_cast(aSenseCode); sl@0: iAdditional = static_cast(aAdditional); sl@0: iQualifier = static_cast(aQualifier); sl@0: } sl@0: sl@0: sl@0: //----------------------------------------------- sl@0: sl@0: /** sl@0: Creates the CScsiProtocol object. Called during controller initialisation. sl@0: sl@0: @param aDriveManager reference to the drive manager object sl@0: */ sl@0: CScsiProtocol* CScsiProtocol::NewL(CDriveManager& aDriveManager) sl@0: { sl@0: CScsiProtocol* self = new (ELeave) CScsiProtocol(aDriveManager); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(); sl@0: CleanupStack::Pop(); sl@0: return self; sl@0: } sl@0: sl@0: /** sl@0: c'tor sl@0: sl@0: @param aDriveManager reference to the drive manager object sl@0: */ sl@0: CScsiProtocol::CScsiProtocol(CDriveManager& aDriveManager): sl@0: iDriveManager(aDriveManager), sl@0: iLastCommand(EUndefinedCommand), sl@0: iLastLun(KUndefinedLun), sl@0: iMediaWriteSize(KDefaultMediaWriteSize) sl@0: { sl@0: __FNLOG("CScsiProtocol::CScsiProtocol"); sl@0: sl@0: #ifdef USB_TRANSFER_PUBLISHER sl@0: iWriteTransferPublisher = CUsbWriteTransferPublisher::NewL(iBytesWritten); sl@0: iReadTransferPublisher = CUsbReadTransferPublisher::NewL(iBytesRead); sl@0: sl@0: for (TUint i = 0; i < KUsbMsMaxDrives; i++) sl@0: { sl@0: iBytesRead[i] = 0; sl@0: iBytesWritten[i] = 0; sl@0: } sl@0: #else sl@0: iWriteTransferPublisher = CDriveWriteTransferPublisher::NewL(aDriveManager.iDrives); sl@0: iReadTransferPublisher = CDriveReadTransferPublisher::NewL(aDriveManager.iDrives); sl@0: #endif sl@0: } sl@0: sl@0: sl@0: CScsiProtocol::~CScsiProtocol() sl@0: { sl@0: __FNLOG("CScsiProtocol::~CScsiProtocol"); sl@0: #ifdef MSDC_MULTITHREADED sl@0: __PRINT(_L("Deleting WriteDrive Thread")); sl@0: delete iWriteDriveThread; sl@0: __PRINT(_L("Deleting ReadDrive Thread")); sl@0: delete iReadDriveThread; sl@0: #endif // MSDC_MULTITHREADED sl@0: sl@0: delete iWriteTransferPublisher; sl@0: delete iReadTransferPublisher; sl@0: } sl@0: sl@0: sl@0: void CScsiProtocol::ConstructL() sl@0: { sl@0: __FNLOG("CScsiProtocol::ConstructL"); sl@0: #ifdef MSDC_MULTITHREADED sl@0: __PRINT(_L("Creating WriteDrive Thread")); sl@0: iWriteDriveThread = CWriteDriveThread::NewL(); sl@0: __PRINT(_L("Creating ReadDrive Thread")); sl@0: iReadDriveThread = CReadDriveThread::NewL(); sl@0: #endif // MSDC_MULTITHREADED sl@0: } sl@0: sl@0: sl@0: /** sl@0: Associates the transport with the protocol. Called during initialisation of the controller. sl@0: sl@0: @param aTransport pointer to the transport object sl@0: */ sl@0: void CScsiProtocol::RegisterTransport(MTransportBase* aTransport) sl@0: { sl@0: __FNLOG("CScsiProtocol::RegisterTransport"); sl@0: iTransport = aTransport; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Called by the Transport when it detects that the USB device is either running sl@0: at High Speed or is at least capable of HS operation. The Protocol can use this sl@0: information (for instance) to select the optimal write block size to use. sl@0: sl@0: This function is preferably called before actual MS data transfer operation sl@0: starts, and usually only once. sl@0: sl@0: */ sl@0: void CScsiProtocol::ReportHighSpeedDevice() sl@0: { sl@0: __FNLOG("CScsiProtocol::ReportHighSpeedDevice"); sl@0: iMediaWriteSize = KHsMediaWriteSize; sl@0: __PRINT1(_L("HS Device reported: SCSI will use %d bytes disk write size"), iMediaWriteSize); sl@0: } sl@0: sl@0: sl@0: TInt CScsiProtocol::SetScsiParameters(TMassStorageConfig aConfig) sl@0: { sl@0: __FNLOG("CScsiProtocol::SetScsiParameters"); sl@0: iConfig = aConfig; sl@0: return KErrNone; sl@0: } sl@0: sl@0: #ifdef MSDC_MULTITHREADED sl@0: sl@0: void CScsiProtocol::ProcessWriteComplete (TUint8* aAddress, TAny* aPtr) sl@0: { sl@0: ((CScsiProtocol*)aPtr)->iTransport->ProcessReadData(aAddress); sl@0: } sl@0: sl@0: void CScsiProtocol::InitializeBufferPointers(TPtr8& aDes1, TPtr8& aDes2) // Todo Change name later - InitializeReadBufferSomething sl@0: { sl@0: iReadDriveThread->iThreadContext->iBuffer.SetUpReadBuf(aDes1, aDes2); sl@0: } sl@0: #endif sl@0: sl@0: /** sl@0: Called by the transport layer when a packet is available for decoding. sl@0: If an error occurs, the sense code is updated and EFalse is returned. sl@0: sl@0: @param aData sl@0: sl@0: @return ETrue if command was decoded and executed successfully sl@0: */ sl@0: TBool CScsiProtocol::DecodePacket(TPtrC8& aData, TUint aLun) sl@0: { sl@0: __FNLOG("CScsiProtocol::DecodePacket"); sl@0: sl@0: TUint8 command = aData[1]; sl@0: sl@0: if (command != ERequestSense) sl@0: { sl@0: iSenseInfo.SetSense(TSenseInfo::ENoSense); sl@0: } sl@0: sl@0: __PRINT2(_L("command = 0x%x lun=%d"), command, aLun); sl@0: switch (command) sl@0: { sl@0: case ETestUnitReady: sl@0: HandleUnitReady(aLun); sl@0: break; sl@0: sl@0: case ERequestSense: sl@0: HandleRequestSense(aData); sl@0: break; sl@0: sl@0: case EInquiry: sl@0: HandleInquiry(aData, aLun); sl@0: break; sl@0: sl@0: case EModeSense: sl@0: HandleModeSense(aData, aLun); sl@0: break; sl@0: sl@0: case EStartStopUnit: sl@0: HandleStartStopUnit(aData, aLun); sl@0: break; sl@0: sl@0: case EPreventMediaRemoval: sl@0: HandlePreventMediaRemoval(aData, aLun); sl@0: break; sl@0: sl@0: case EReadCapacity: sl@0: HandleReadCapacity(aData, aLun); sl@0: break; sl@0: sl@0: case ERead10: sl@0: HandleRead10(aData, aLun); sl@0: break; sl@0: sl@0: case EWrite10: sl@0: HandleWrite10(aData,aLun); sl@0: break; sl@0: sl@0: case EVerify10: sl@0: HandleVerify10(aData, aLun); sl@0: break; sl@0: sl@0: case EReadFormatCapacities: sl@0: HandleReadFormatCapacities(aLun); sl@0: break; sl@0: sl@0: default: sl@0: iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidCmdCode); sl@0: } sl@0: __PRINT1(_L("DecodePacket result = %d"), iSenseInfo.SenseOk()); sl@0: return(iSenseInfo.SenseOk()); sl@0: } sl@0: sl@0: sl@0: /** sl@0: Checks if drive ready sl@0: sl@0: @param aLun Logic unit number sl@0: @return pointer to drive correspondent to LUN if drive mounted and ready, NULL otherwise sl@0: */ sl@0: CMassStorageDrive* CScsiProtocol::GetCheckDrive(TUint aLun) sl@0: { sl@0: __FNLOG("CScsiProtocol::GetCheckDrive"); sl@0: TInt err=KErrNone; sl@0: sl@0: #ifdef MSDC_MULTITHREADED sl@0: // check for deferred errors sl@0: if (iWriteDriveThread->DeferredError()) sl@0: { sl@0: iWriteDriveThread->ClearDeferredError(); sl@0: iDeferredSenseInfo.SetSense(TSenseInfo::EMediumError); sl@0: return NULL; sl@0: } sl@0: sl@0: #endif sl@0: sl@0: CMassStorageDrive* drive= iDriveManager.Drive(aLun, err); sl@0: sl@0: if (err !=KErrNone || drive == NULL) sl@0: { sl@0: __PRINT(_L("No drive available\n")); sl@0: iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::ELuNotSupported); sl@0: return NULL; sl@0: } sl@0: sl@0: CMassStorageDrive::TMountState mountState = drive->MountState(); sl@0: sl@0: if (mountState == CMassStorageDrive::EDisconnected || mountState == CMassStorageDrive::EConnecting) sl@0: { sl@0: __PRINT(_L("Drive disconnected\n")); sl@0: iSenseInfo.SetSense(TSenseInfo::ENotReady, sl@0: TSenseInfo::EMediaNotPresent); sl@0: return NULL; sl@0: } sl@0: sl@0: CMassStorageDrive::TDriveState state = drive->CheckDriveState(); sl@0: if (state == CMassStorageDrive::EMediaNotPresent || state == CMassStorageDrive::ELocked) sl@0: { sl@0: __PRINT1(_L("Media not present or locked. (state =0x%X)\n"),state); sl@0: iSenseInfo.SetSense(TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent); sl@0: return NULL; sl@0: } sl@0: sl@0: if (drive->IsMediaChanged(ETrue)) //reset "media changed" status sl@0: { sl@0: __PRINT(_L("Media was changed\n")); sl@0: // SAM-2 Section 5.9.5 Unit Attention Condition sl@0: iSenseInfo.SetSense(TSenseInfo::EUnitAttention, TSenseInfo::ENotReadyToReadyChange); sl@0: iDriveManager.Connect(aLun); //publish event to USB app sl@0: return NULL; sl@0: } sl@0: sl@0: if (mountState == CMassStorageDrive::EDisconnecting) sl@0: { sl@0: __PRINT(_L("Drive disconnecting\n")); sl@0: iSenseInfo.SetSense(TSenseInfo::ENotReady, sl@0: TSenseInfo::EMediaNotPresent); sl@0: return NULL; sl@0: } sl@0: sl@0: return drive; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Command Parser for the UNIT READY command (0x00) sl@0: sl@0: @param aLun Logic unit number sl@0: @return ETrue if successful, sl@0: */ sl@0: TBool CScsiProtocol::HandleUnitReady(TUint aLun) sl@0: { sl@0: __FNLOG("CScsiProtocol::HandleUnitReady"); sl@0: #ifdef MSDC_MULTITHREADED sl@0: iWriteDriveThread->WaitForWriteEmpty(); sl@0: #endif sl@0: return GetCheckDrive(aLun) ? (TBool)ETrue : (TBool)EFalse; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Command Parser for the REQUEST SENSE command (0x03) sl@0: sl@0: @return ETrue if successful, sl@0: */ sl@0: TBool CScsiProtocol::HandleRequestSense(TPtrC8& aData) sl@0: { sl@0: __FNLOG("CScsiProtocol::HandleRequestSense"); sl@0: TUint length = aData[5]; sl@0: __PRINT1(_L("length = %d\n"), length); sl@0: sl@0: TPtr8 writeBuf(NULL, 0); sl@0: iTransport->GetCommandBufPtr(writeBuf, KRequestSenseCommandLength); sl@0: writeBuf.FillZ(KRequestSenseCommandLength); sl@0: sl@0: TSenseInfo* senseInfo; sl@0: #ifdef MSDC_MULTITHREADED sl@0: if (!iDeferredSenseInfo.SenseOk()) sl@0: { sl@0: writeBuf[00] = 0x71; //(deferred errors) sl@0: senseInfo = &iDeferredSenseInfo; sl@0: } sl@0: else sl@0: { sl@0: writeBuf[00] = 0x70; //(current errors) sl@0: senseInfo = &iSenseInfo; sl@0: } sl@0: #else sl@0: senseInfo = &iSenseInfo; sl@0: writeBuf[00] = 0x70; //(current errors) sl@0: #endif sl@0: sl@0: writeBuf[02] = static_cast(senseInfo->iSenseCode & 0x0F); sl@0: sl@0: writeBuf[12] = senseInfo->iAdditional; sl@0: writeBuf[13] = senseInfo->iQualifier; sl@0: if (length<18 && length >=8) sl@0: { sl@0: writeBuf.SetLength(length); //length of response code data sl@0: writeBuf[07] = TUint8(length - 8); //additional sence length sl@0: } sl@0: else if (length >= KRequestSenseCommandLength) sl@0: { sl@0: writeBuf[07] = KRequestSenseCommandLength - 8; // we have max 18 byte to send sl@0: } sl@0: sl@0: __PRINT4(_L("Response=0x%x Sense=0x%x, Additional=0x%x, Qualifier=0x%x\n"), sl@0: writeBuf[0], writeBuf[02], writeBuf[12], writeBuf[13]); sl@0: sl@0: TPtrC8 writeBuf1 = writeBuf.Left(length); sl@0: sl@0: iTransport->SetupWriteData(writeBuf1); sl@0: sl@0: // clear the sense info sl@0: iSenseInfo.SetSense(TSenseInfo::ENoSense); sl@0: sl@0: #ifdef MSDC_MULTITHREADED sl@0: iDeferredSenseInfo.SetSense(TSenseInfo::ENoSense); sl@0: #endif sl@0: sl@0: return ETrue; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Command Parser for the INQUIRY command (0x12) sl@0: sl@0: @param aLun Logic unit number sl@0: @return ETrue if successful, sl@0: */ sl@0: TBool CScsiProtocol::HandleInquiry(TPtrC8& aData, TUint aLun ) sl@0: { sl@0: __FNLOG("CScsiProtocol::HandleInquiry"); sl@0: sl@0: TBool cmdDt = aData[2] & 0x2; sl@0: TBool evpd = aData[2] & 0x1; sl@0: TUint8 page = aData[3]; sl@0: if (cmdDt || evpd || page || aLun >= KUsbMsMaxDrives) sl@0: { sl@0: iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb); sl@0: return EFalse; sl@0: } sl@0: sl@0: TPtr8 writeBuf(NULL, 0); sl@0: iTransport->GetCommandBufPtr(writeBuf, KInquiryCommandLength); sl@0: writeBuf.FillZ(KInquiryCommandLength); sl@0: sl@0: writeBuf[1] = 0x80; // MSB: RMB : Removable sl@0: writeBuf[3] = 0x02; // AERC, TrmTsk, NormACA, Response Data Format sl@0: writeBuf[4] = 0x1F; // Additional Length sl@0: sl@0: TPtr8 vendorId(&writeBuf[8], 8, 8); // Vendor ID (Vendor Specific/Logged by T10) sl@0: vendorId.Fill(' ', 8); sl@0: vendorId.Copy(iConfig.iVendorId); sl@0: sl@0: TPtr8 productId(&writeBuf[16], 16, 16); // Product ID (Vendor Specific) sl@0: productId.Fill(' ', 16); sl@0: productId.Copy(iConfig.iProductId); sl@0: sl@0: TPtr8 productRev(&writeBuf[32], 4, 4); // Product Revision Level (Vendor Specific) sl@0: productRev.Fill(' ', 4); sl@0: productRev.Copy(iConfig.iProductRev); sl@0: sl@0: TUint length = aData[5]; sl@0: sl@0: TPtrC8 writeBuf1 = writeBuf.Left(length); sl@0: iTransport->SetupWriteData(writeBuf1); sl@0: sl@0: iSenseInfo.SetSense(TSenseInfo::ENoSense); sl@0: return ETrue; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Command Parser for the START STOP UNIT command (0x1B) sl@0: sl@0: @param aData command data (started form position 1) sl@0: @param aLun Logic unit number sl@0: @return ETrue if successful, TFalse otherwise sl@0: */ sl@0: TBool CScsiProtocol::HandleStartStopUnit(TPtrC8& aData, TUint aLun) sl@0: { sl@0: __FNLOG("CScsiProtocol::HandleStartStopUnit"); sl@0: sl@0: const TUint8 KStartMask = 0x01; sl@0: const TUint8 KImmedMask = 0x01; sl@0: const TUint8 KLoejMask = 0x02; sl@0: sl@0: TBool immed = aData[2] & KImmedMask ? (TBool)ETrue : (TBool)EFalse; sl@0: TBool start = aData[5] & KStartMask ? (TBool)ETrue : (TBool)EFalse; sl@0: TBool loej = aData[5] & KLoejMask ? (TBool)ETrue : (TBool)EFalse; sl@0: sl@0: __PRINT2(_L("Data %X %X\n"), aData[2], aData[5]); sl@0: __PRINT1(_L("IMMED = %d\n"), immed); sl@0: __PRINT1(_L("START = %d\n"), start); sl@0: sl@0: __PRINT1(_L("LOEJ = %d\n"), loej); sl@0: sl@0: TInt err(KErrNone); sl@0: if (loej) sl@0: { sl@0: if(start) //Start unit sl@0: { sl@0: err = iDriveManager.Connect(aLun); sl@0: __PRINT(_L("Load media\n")); sl@0: sl@0: #ifdef USB_TRANSFER_PUBLISHER sl@0: iBytesRead[aLun] = 0; sl@0: iBytesWritten[aLun] = 0; sl@0: #endif sl@0: // publish the initial values sl@0: iWriteTransferPublisher->DoPublishDataTransferredEvent(); sl@0: iReadTransferPublisher->DoPublishDataTransferredEvent(); sl@0: } sl@0: else //Stop unit sl@0: { sl@0: iDriveManager.SetCritical(aLun, EFalse); sl@0: err = iDriveManager.Disconnect(aLun); sl@0: __PRINT(_L("Unload media\n")); sl@0: } sl@0: } sl@0: sl@0: if (err !=KErrNone) //actually we have error here only if the LUN is incorrect sl@0: { sl@0: iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::ELuNotSupported); sl@0: return EFalse; sl@0: } sl@0: if (immed) sl@0: { sl@0: return ETrue; sl@0: } sl@0: sl@0: CMassStorageDrive* drive= iDriveManager.Drive(aLun, err); sl@0: sl@0: if (err !=KErrNone || drive == NULL) sl@0: { sl@0: iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::ELuNotSupported); sl@0: return EFalse; sl@0: } sl@0: sl@0: TInt timeLeft (20); // 1 sec timeout sl@0: CMassStorageDrive::TMountState mountState; sl@0: sl@0: do sl@0: { sl@0: User::After(1000 * 50); // 50 mSec sl@0: --timeLeft; sl@0: mountState = drive->MountState(); sl@0: sl@0: if ((!start && mountState != CMassStorageDrive::EConnected) sl@0: || sl@0: (start && sl@0: (mountState == CMassStorageDrive::EDisconnecting || sl@0: mountState == CMassStorageDrive::EConnected)) sl@0: ) sl@0: { sl@0: return ETrue; sl@0: } sl@0: } while (timeLeft>0); sl@0: sl@0: //timeout happend sl@0: iSenseInfo.SetSense(TSenseInfo::ENotReady, sl@0: TSenseInfo::EAscLogicalUnitDoesNotRespondToSelection); sl@0: return EFalse; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Command Parser for the PREVENT/ALLOW MEDIA REMOVAL command (0x1E) sl@0: sl@0: @param aData command data (started form position 1) sl@0: @param aLun Logic unit number sl@0: @return ETrue if successful. sl@0: */ sl@0: TBool CScsiProtocol::HandlePreventMediaRemoval(TPtrC8& aData, TUint aLun) sl@0: { sl@0: __FNLOG("CScsiProtocol::HandlePreventMediaRemoval"); sl@0: CMassStorageDrive* drive=GetCheckDrive(aLun); sl@0: sl@0: if (drive == NULL) sl@0: { sl@0: return EFalse; sl@0: } sl@0: sl@0: TInt prevent = aData[5] & 0x01; sl@0: __PRINT1(_L("prevent = %d\n"), prevent); sl@0: iDriveManager.SetCritical(aLun, prevent); sl@0: sl@0: return ETrue; sl@0: } sl@0: sl@0: sl@0: /** Cancel active state, Invoked by transnport when it stops */ sl@0: TInt CScsiProtocol::Cancel() sl@0: { sl@0: iDriveManager.SetCritical(CDriveManager::KAllLuns, EFalse); sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: TBool CScsiProtocol::HandleReadFormatCapacities(TUint aLun) sl@0: /** sl@0: * Command Parser for the READ FORMAT CAPACITIES command (0x23) sl@0: * sl@0: * @return ETrue if successful, else a standard Symbian OS error code. sl@0: */ sl@0: { sl@0: __FNLOG("CScsiProtocol::HandleReadFormatCapacities"); sl@0: sl@0: CMassStorageDrive* drive=GetCheckDrive(aLun); sl@0: sl@0: if (drive == NULL) sl@0: { sl@0: return EFalse; sl@0: } sl@0: sl@0: TLocalDriveCapsV4 driveInfo; sl@0: sl@0: TInt err = drive->Caps(driveInfo); sl@0: sl@0: if(err != KErrNone) sl@0: { sl@0: __PRINT1(_L("Can't obtain drive Caps. Err=%d \n"),err); sl@0: iSenseInfo.SetSense(TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent); sl@0: return EFalse; sl@0: } sl@0: sl@0: TInt64 driveBlocks = (driveInfo.iDriveAtt & KDriveAttLogicallyRemovable) ? driveInfo.iSize : driveInfo.MediaSizeInBytes(); sl@0: driveBlocks /= MAKE_TINT64(0, KDefaultBlockSize); sl@0: sl@0: TPtr8 writeBuf(NULL, 0); sl@0: iTransport->GetCommandBufPtr(writeBuf, KReadFormatCapacitiesCommandLength); sl@0: writeBuf.FillZ(KReadFormatCapacitiesCommandLength); sl@0: sl@0: writeBuf[3] = 0x08; // Capacity List Length sl@0: sl@0: TUint32 numBlocks = I64LOW(driveBlocks); sl@0: sl@0: writeBuf[4] = static_cast((numBlocks & 0xFF000000) >> 24); // Number of blocks sl@0: writeBuf[5] = static_cast((numBlocks & 0x00FF0000) >> 16); // sl@0: writeBuf[6] = static_cast((numBlocks & 0x0000FF00) >> 8); // sl@0: writeBuf[7] = static_cast((numBlocks & 0x000000FF)); // sl@0: sl@0: writeBuf[8] = 0x02; // Formatted size sl@0: sl@0: writeBuf[9] = 0x00; // 512 Byte Blocks sl@0: writeBuf[10] = 0x02; // sl@0: writeBuf[11] = 0x00; // sl@0: sl@0: TPtrC8 writeBuf1 = writeBuf; sl@0: sl@0: iTransport->SetupWriteData(writeBuf1); sl@0: sl@0: return ETrue; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Command Parser for the READ CAPACITY(10) command (0x25) sl@0: sl@0: @param aData command data (started form position 1) sl@0: @param aLun Logic unit number sl@0: @return ETrue if successful. sl@0: */ sl@0: TBool CScsiProtocol::HandleReadCapacity(TPtrC8& aData, TUint aLun) sl@0: { sl@0: __FNLOG("CScsiProtocol::HandleReadCapacity"); sl@0: CMassStorageDrive* drive=GetCheckDrive(aLun); sl@0: sl@0: if (drive == NULL) sl@0: { sl@0: return EFalse; sl@0: } sl@0: sl@0: TInt pmi = aData[9] & 0x01; sl@0: TInt lba = aData[3] | aData[4] | aData[5] | aData[6]; sl@0: sl@0: if (pmi || lba) //do not support partial medium indicator sl@0: { sl@0: iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb); sl@0: return EFalse; sl@0: } sl@0: sl@0: TLocalDriveCapsV4 driveInfo; sl@0: sl@0: TInt err = drive->Caps(driveInfo); sl@0: sl@0: if(err != KErrNone) sl@0: { sl@0: __PRINT1(_L("Can't obtain drive Caps. Err=%d \n"),err); sl@0: iSenseInfo.SetSense(TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent); sl@0: return EFalse; sl@0: } sl@0: sl@0: TInt64 driveBlocks = 0; sl@0: if (driveInfo.iDriveAtt & KDriveAttLogicallyRemovable) sl@0: { sl@0: // Partition Access only sl@0: driveBlocks = driveInfo.iSize / MAKE_TINT64(0, KDefaultBlockSize); sl@0: } sl@0: else sl@0: { sl@0: // whole Media Access sl@0: driveBlocks = driveInfo.MediaSizeInBytes() / MAKE_TINT64(0, KDefaultBlockSize) - 1; sl@0: } sl@0: sl@0: sl@0: TPtr8 writeBuf(NULL, 0); sl@0: iTransport->GetCommandBufPtr(writeBuf, KReadCapacityCommandLength); sl@0: writeBuf.FillZ(KReadCapacityCommandLength); sl@0: sl@0: if (I64HIGH(driveBlocks) == 0) sl@0: { sl@0: TUint32 numBlocks = I64LOW(driveBlocks); sl@0: sl@0: __PRINT2(_L("Block size=%d, NumBlocks=%d\n"), KDefaultBlockSize, numBlocks); sl@0: writeBuf[0] = static_cast((numBlocks & 0xFF000000) >> 24); // Number of blocks sl@0: writeBuf[1] = static_cast((numBlocks & 0x00FF0000) >> 16); sl@0: writeBuf[2] = static_cast((numBlocks & 0x0000FF00) >> 8); sl@0: writeBuf[3] = static_cast((numBlocks & 0x000000FF)); sl@0: } sl@0: else sl@0: { sl@0: writeBuf[0] = writeBuf[1] = writeBuf[2] = writeBuf[3] = 0xFF; // indicate that size more then )0xFFFFFFFF sl@0: } sl@0: sl@0: writeBuf[4] = static_cast((KDefaultBlockSize & 0xFF000000) >> 24); // Block Size sl@0: writeBuf[5] = static_cast((KDefaultBlockSize & 0x00FF0000) >> 16); sl@0: writeBuf[6] = static_cast((KDefaultBlockSize & 0x0000FF00) >> 8); sl@0: writeBuf[7] = static_cast((KDefaultBlockSize & 0x000000FF)); sl@0: sl@0: TPtrC8 writeBuf1 = writeBuf; sl@0: iTransport->SetupWriteData(writeBuf1); sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Command Parser for the READ10 command (0x28) sl@0: sl@0: @param aData command data (started form position 1) sl@0: @param aLun Logic unit number sl@0: @return ETrue if successful. sl@0: */ sl@0: TBool CScsiProtocol::HandleRead10(TPtrC8& aData, TUint aLun) sl@0: { sl@0: __FNLOG("CScsiProtocol::HandleRead10"); sl@0: CMassStorageDrive* drive = GetCheckDrive(aLun); sl@0: if (drive == NULL) sl@0: { sl@0: return EFalse; sl@0: } sl@0: TInt rdProtect = aData[2] >> 5; sl@0: if (rdProtect) sl@0: { sl@0: iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb); sl@0: return EFalse; sl@0: } sl@0: sl@0: const TUint32 lba = LBA(aData); sl@0: const TUint16 len = LEN(aData); sl@0: sl@0: __PRINT2(_L("READ(10) : LBA = 0x%x, Length = %d (blocks)\n"), lba, len); sl@0: sl@0: if (!len) sl@0: { sl@0: return ETrue; // do nothing - this is not an error sl@0: } sl@0: sl@0: TLocalDriveCapsV4 driveInfo; sl@0: TInt err = drive->Caps(driveInfo); sl@0: if (err != KErrNone) sl@0: { sl@0: __PRINT1(_L("Can't obtain drive Caps. Err=%d \n"), err); sl@0: iSenseInfo.SetSense(TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent); sl@0: return EFalse; sl@0: } sl@0: sl@0: const TInt64 bOffset = MAKE_TINT64(0, lba) * KDefaultBlockSize; sl@0: const TInt bLength = len * KDefaultBlockSize; sl@0: const TInt64 theEnd = bOffset + MAKE_TINT64(0, bLength); sl@0: const TInt64 mediaSize = (driveInfo.iDriveAtt & KDriveAttLogicallyRemovable) ? driveInfo.iSize : driveInfo.MediaSizeInBytes() ; sl@0: sl@0: if (theEnd > mediaSize) //check if media big enough for this request sl@0: { sl@0: __PRINT(_L("err - Request ends out of media\n")); sl@0: iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::ELbaOutOfRange); sl@0: return EFalse; sl@0: } sl@0: sl@0: #ifdef MSDC_MULTITHREADED sl@0: iWriteDriveThread->WaitForWriteEmpty(); sl@0: sl@0: // check if our buffer can hold requested data sl@0: if (iReadDriveThread->iThreadContext->MaxBufferLength() < bLength) sl@0: { sl@0: __PRINT(_L("err - Buffer too small\n")); sl@0: iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb); sl@0: return EFalse; sl@0: } sl@0: sl@0: // Optimisation note : If the host is reading from sectors it just wrote to, sl@0: // then we have to force a cache-miss so that the real data is read from the sl@0: // drive. It would be possible to service the read from the write buffers, sl@0: // but as the host is probably trying to verify the write data, we don't do sl@0: // that for now. sl@0: if (!iReadDriveThread->ReadDriveData(drive, bOffset, bLength, iWriteDriveThread->IsRecentlyWritten(bOffset,bLength))) sl@0: { sl@0: iSenseInfo.SetSense(TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent); sl@0: return EFalse; sl@0: } sl@0: sl@0: iWriteDriveThread->SetCommandWrite10(EFalse); sl@0: TBlockDesc* &desc = iReadDriveThread->iThreadContext->iBuffer.iDescReadPtr; sl@0: TPtrC8 writeBuf1 = desc->iBuf; sl@0: #else sl@0: sl@0: TPtr8 writeBuf(NULL, 0); sl@0: iTransport->GetReadDataBufPtr(writeBuf); sl@0: // check if our buffer can hold requested data sl@0: if (writeBuf.MaxLength() < bLength) sl@0: { sl@0: __PRINT(_L("err - Buffer too small\n")); sl@0: iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb); sl@0: return EFalse; sl@0: } sl@0: sl@0: err = drive->Read(bOffset, bLength, writeBuf, drive->IsWholeMediaAccess()); sl@0: sl@0: if (err != KErrNone) sl@0: { sl@0: __PRINT1(_L("Read failed, err=%d\n"), err); sl@0: iSenseInfo.SetSense(TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent); sl@0: return EFalse; sl@0: } sl@0: sl@0: TPtrC8 writeBuf1 = writeBuf; sl@0: #endif // MSDC_MULTITHREADED sl@0: #ifdef USB_TRANSFER_PUBLISHER sl@0: iBytesRead[aLun] += writeBuf1.Length(); sl@0: #endif sl@0: iReadTransferPublisher->StartTimer(); sl@0: sl@0: // Set up data write to the host sl@0: iTransport->SetupWriteData(writeBuf1); sl@0: sl@0: return ETrue; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Command Parser for the WRITE(10) command (0x2A) sl@0: sl@0: @param aData command data (started form position 1) sl@0: @param aLun Logic unit number sl@0: @return ETrue if successful. sl@0: */ sl@0: TBool CScsiProtocol::HandleWrite10(TPtrC8& aData, TUint aLun) sl@0: { sl@0: __FNLOG("CScsiProtocol::HandleWrite10"); sl@0: CMassStorageDrive* drive = GetCheckDrive(aLun); sl@0: if (drive == NULL) sl@0: { sl@0: return EFalse; sl@0: } sl@0: TInt wrProtect = aData[2] >> 5; sl@0: if (wrProtect) sl@0: { sl@0: iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb); sl@0: return EFalse; sl@0: } sl@0: sl@0: const TUint32 lba = LBA(aData); sl@0: const TUint16 len = LEN(aData); sl@0: __PRINT2(_L("WRITE(10) : LBA = 0x%x, Length = %d (blocks)\n"), lba, len); sl@0: if (!len) sl@0: { sl@0: return ETrue; // do nothing - this is not an error sl@0: } sl@0: sl@0: TLocalDriveCapsV4 driveInfo; sl@0: TInt err = drive->Caps(driveInfo); sl@0: if (err != KErrNone) sl@0: { sl@0: __PRINT1(_L("Can't obtain drive Caps. Err=%d \n"), err); sl@0: iSenseInfo.SetSense(TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent); sl@0: return EFalse; sl@0: } sl@0: if (driveInfo.iMediaAtt & KMediaAttWriteProtected || sl@0: driveInfo.iMediaAtt & KMediaAttLocked) sl@0: { sl@0: iSenseInfo.SetSense(TSenseInfo::EDataProtection, TSenseInfo::EWriteProtected); sl@0: return EFalse; sl@0: } sl@0: sl@0: const TInt64 bOffset = MAKE_TINT64(0, lba) * KDefaultBlockSize; sl@0: iBytesRemain = len * KDefaultBlockSize; sl@0: const TInt64 theEnd = bOffset + MAKE_TINT64(0, iBytesRemain); sl@0: const TInt64 mediaSize = (driveInfo.iDriveAtt & KDriveAttLogicallyRemovable) ? driveInfo.iSize : driveInfo.MediaSizeInBytes() ; sl@0: sl@0: if (theEnd > mediaSize) //check if media big enough for this request sl@0: { sl@0: __PRINT(_L("err - Request ends out of media\n")); sl@0: iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::ELbaOutOfRange); sl@0: return EFalse; sl@0: } sl@0: sl@0: #ifdef MSDC_MULTITHREADED sl@0: iWriteDriveThread->SetCommandWrite10(ETrue); sl@0: #endif sl@0: sl@0: // Set up the first request for data from the host - either sl@0: // KMaxBufSize or the entire transfer length, whichever is smallest. sl@0: TUint thisLength = (iBytesRemain > KMaxBufSize) ? KMaxBufSize : iBytesRemain; sl@0: thisLength = (thisLength > iMediaWriteSize) ? iMediaWriteSize : thisLength; sl@0: sl@0: iOffset = bOffset; sl@0: iLastCommand = EWrite10; sl@0: iLastLun = aLun; sl@0: sl@0: iWriteTransferPublisher->StartTimer(); sl@0: iTransport->SetupReadData(thisLength); sl@0: sl@0: return ETrue; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Command Parser for the VERIFY(10) command (0x2F) sl@0: sl@0: @param aData command data (started form position 1) sl@0: @param aLun Logic unit number sl@0: @return ETrue if successful. sl@0: */ sl@0: TBool CScsiProtocol::HandleVerify10(TPtrC8& aData, TUint aLun) sl@0: { sl@0: __FNLOG("CScsiProtocol::HandleVerify10"); sl@0: CMassStorageDrive* drive = GetCheckDrive(aLun); sl@0: if (drive == NULL) sl@0: { sl@0: return EFalse; sl@0: } sl@0: sl@0: TInt vrProtect = aData[2] >> 5; sl@0: if (vrProtect) sl@0: { sl@0: iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb); sl@0: return EFalse; sl@0: } sl@0: sl@0: const TUint32 lba = LBA(aData); sl@0: const TUint16 len = LEN(aData); sl@0: __PRINT2(_L("VERIFY(10) : LBA = %d, Length = %d (blocks)\n"), lba, len); sl@0: sl@0: TInt bytChk = aData[2] & 0x02; sl@0: if (!len) sl@0: { sl@0: return ETrue; // do nothing - this is not an error sl@0: } sl@0: sl@0: TLocalDriveCapsV4 driveInfo; sl@0: TInt err = drive->Caps(driveInfo); sl@0: if (err != KErrNone) sl@0: { sl@0: __PRINT1(_L("Can't obtain drive Caps. Err=%d \n"), err); sl@0: iSenseInfo.SetSense(TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent); sl@0: return EFalse; sl@0: } sl@0: sl@0: const TInt64 bOffset = MAKE_TINT64(0, lba) * KDefaultBlockSize; sl@0: const TInt bLength = len * KDefaultBlockSize; sl@0: const TInt64 theEnd = bOffset + MAKE_TINT64(0, bLength); sl@0: const TInt64 mediaSize = (driveInfo.iDriveAtt & KDriveAttLogicallyRemovable) ? driveInfo.iSize : driveInfo.MediaSizeInBytes() ; sl@0: sl@0: // check if media big enough for this request sl@0: if (theEnd > mediaSize) sl@0: { sl@0: iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::ELbaOutOfRange); sl@0: return EFalse; sl@0: } sl@0: sl@0: // check if our buffer can hold requested data sl@0: #ifdef MSDC_MULTITHREADED sl@0: if (iWriteDriveThread->iThreadContext->MaxBufferLength() < bLength) sl@0: #else sl@0: TPtr8 writeBuf(NULL, 0); sl@0: iTransport->GetReadDataBufPtr(writeBuf); sl@0: if (writeBuf.MaxLength() < bLength) sl@0: #endif sl@0: { sl@0: iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb); sl@0: return EFalse; sl@0: } sl@0: sl@0: if (!bytChk) sl@0: { sl@0: // BYTCHK==0 : Perform a medium verification with no data comparison and not transfer any data from the application client data-out buffer. sl@0: // The device should attempt to read from the specified locations sl@0: #ifdef MSDC_MULTITHREADED sl@0: TPtr8 writeBuf = iWriteDriveThread->iThreadContext->GetReadBuffer(bLength); sl@0: #else sl@0: writeBuf.SetLength(bLength); sl@0: #endif sl@0: err = drive->Read(bOffset, bLength, writeBuf, drive->IsWholeMediaAccess()); sl@0: if (err != KErrNone) sl@0: { sl@0: iSenseInfo.SetSense(TSenseInfo::EMisCompare); sl@0: return EFalse; sl@0: } sl@0: return ETrue; sl@0: } sl@0: sl@0: // BYTCHK==1 : perform a byte-by-byte comparison of user data read from the medium & user data transferred from the application client data-out buffer. sl@0: // The host sends data in the data-transport phase, and the device should verify that the received data matches what is stored in the device. sl@0: sl@0: iOffset = bOffset; sl@0: iLastCommand = EVerify10; sl@0: iLastLun = aLun; sl@0: sl@0: iTransport->SetupReadData(bLength); sl@0: sl@0: return ETrue; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Called by the transport when the requested data has been read or an error has sl@0: occurred during the read. sl@0: sl@0: @param aError Indicate if an error occurs during reading data by transport. sl@0: @return KErrAbort if command processing is complete but has failed, sl@0: KErrCompletion if sufficient data is available in the buffer to process sl@0: the transfer immediately, KErrNotReady if insufficient data is sl@0: available in the buffer so the transport should wait for it to arrive, sl@0: KErrNone if command processing is complete and was successful. sl@0: */ sl@0: TInt CScsiProtocol::ReadComplete(TInt aError) sl@0: { sl@0: __FNLOG("CScsiProtocol::ReadComplete"); sl@0: __PRINT1(_L("Error = 0x%X \n"), aError); sl@0: const TInt64 bOffset = iOffset; sl@0: TUint8 lastCommand = iLastCommand; sl@0: TUint lastLun = iLastLun; sl@0: sl@0: iOffset = 0; sl@0: iLastCommand = EUndefinedCommand; sl@0: iLastLun = KUndefinedLun; sl@0: sl@0: __PRINT1(_L("Last command was: %s\n"), sl@0: (lastCommand == EUndefinedCommand) ? _S("Undefined") : sl@0: ((lastCommand == EWrite10) ? _S("EWrite10") : sl@0: ((lastCommand == EVerify10) ? _S("EVerify10") : sl@0: _S("Unknown")))); sl@0: sl@0: if (aError != KErrNone || sl@0: lastCommand == EUndefinedCommand || sl@0: lastLun == KUndefinedLun) sl@0: { sl@0: iSenseInfo.SetSense(TSenseInfo::EAbortedCommand); sl@0: return KErrAbort; sl@0: } sl@0: sl@0: CMassStorageDrive* drive = GetCheckDrive(lastLun); sl@0: if (drive == NULL) sl@0: { sl@0: return KErrAbort; sl@0: } sl@0: sl@0: if (lastCommand == EWrite10) sl@0: { sl@0: TPtrC8 writeBuf(NULL, 0); sl@0: iTransport->GetWriteDataBufPtr(writeBuf); sl@0: sl@0: #ifdef USB_TRANSFER_PUBLISHER sl@0: iBytesWritten[lastLun] += writeBuf.Length(); sl@0: #endif sl@0: sl@0: #ifdef MSDC_MULTITHREADED sl@0: TInt err = iWriteDriveThread->WriteDriveData(drive, bOffset, writeBuf, ProcessWriteComplete, this); sl@0: sl@0: if (err != KErrNone) sl@0: { sl@0: iDeferredSenseInfo.SetSense(TSenseInfo::EMediumError); sl@0: } sl@0: sl@0: TUint thisLength = iWriteDriveThread->WriteBufferLength(); sl@0: #else sl@0: #ifdef MEASURE_AND_DISPLAY_WRITE_TIME sl@0: RDebug::Print(_L("SCSI: writing %d bytes\n"), writeBuf.Length()); sl@0: TTime t0, t1; sl@0: t0.HomeTime(); sl@0: #else sl@0: __PRINT1(_L("SCSI: writing %d bytes\n"), writeBuf.Length()); sl@0: #endif sl@0: sl@0: #ifdef INJECT_ERROR sl@0: if (writeBuf[0] == '2') sl@0: { sl@0: writeBuf[0] = 'x'; sl@0: RDebug::Printf("Injecting error"); sl@0: } sl@0: sl@0: RDebug::Printf("%08lx %x [%x] [%x]", bOffset,writeBuf.Length(), sl@0: writeBuf[0], sl@0: writeBuf[writeBuf.Length()-1]); sl@0: #endif sl@0: sl@0: TInt err = drive->Write(bOffset, writeBuf, drive->IsWholeMediaAccess()); sl@0: sl@0: #ifdef INJECT_ERROR sl@0: if (writeBuf[0] == 'x') sl@0: { sl@0: err = KErrUnknown; sl@0: } sl@0: #endif sl@0: sl@0: #ifdef MEASURE_AND_DISPLAY_WRITE_TIME sl@0: t1.HomeTime(); sl@0: const TTimeIntervalMicroSeconds time = t1.MicroSecondsFrom(t0); sl@0: const TUint time_ms = I64LOW(time.Int64() / 1000); sl@0: RDebug::Print(_L("SCSI: write took %d ms\n"), time_ms); sl@0: #endif sl@0: if (err != KErrNone) sl@0: { sl@0: __PRINT1(_L("Error after write = 0x%X \n"), err); sl@0: iSenseInfo.SetSense(TSenseInfo::EAbortedCommand); sl@0: return KErrAbort; sl@0: } sl@0: sl@0: TUint thisLength = writeBuf.Length(); sl@0: #endif // MSDC_MULTITHREADED sl@0: iOffset = bOffset + MAKE_TINT64(0, thisLength); sl@0: iBytesRemain -= thisLength; sl@0: if ((TInt)iBytesRemain > 0) sl@0: { sl@0: // More data is expected - set up another request to read from the host sl@0: iLastCommand = EWrite10; sl@0: iLastLun = lastLun; sl@0: sl@0: TUint minLength = (iBytesRemain < iMediaWriteSize) ? iBytesRemain : iMediaWriteSize; sl@0: TUint bytesAvail = iTransport->BytesAvailable() & ~(KDefaultBlockSize-1); sl@0: sl@0: TBool wait = EFalse; sl@0: thisLength = bytesAvail ? bytesAvail : minLength; sl@0: if (thisLength < minLength) sl@0: { sl@0: // Not enough data is available at the transport to satisfy the request, sl@0: // so return KErrNotReady to indicate that the transport should wait. sl@0: thisLength = minLength; sl@0: wait = ETrue; sl@0: } sl@0: sl@0: thisLength = (thisLength > KMaxBufSize) ? KMaxBufSize : thisLength; sl@0: sl@0: iTransport->SetupReadData(thisLength); sl@0: sl@0: return wait ? KErrNotReady : KErrCompletion; sl@0: } sl@0: } sl@0: else if (lastCommand == EVerify10) sl@0: { sl@0: HBufC8* hostData = NULL; sl@0: TPtrC8 writeBuf(NULL, 0); sl@0: iTransport->GetWriteDataBufPtr(writeBuf); sl@0: #ifdef MSDC_MULTITHREADED sl@0: TRAPD(err, hostData = HBufC8::NewL(writeBuf.Length())); sl@0: #else sl@0: TRAPD(err, hostData = HBufC8::NewL(writeBuf.Length())); sl@0: #endif sl@0: if (err != KErrNone || hostData == NULL) sl@0: { sl@0: iSenseInfo.SetSense(TSenseInfo::EAbortedCommand, TSenseInfo::EInsufficientRes); sl@0: return KErrAbort; sl@0: } sl@0: sl@0: #ifdef MSDC_MULTITHREADED sl@0: // copy the data sl@0: *hostData = writeBuf; sl@0: TPtr8 readBuf = iWriteDriveThread->iThreadContext->GetReadBuffer(); sl@0: err = drive->Read(bOffset, writeBuf.Length(), readBuf, drive->IsWholeMediaAccess()); sl@0: if (err == KErrNone) sl@0: { sl@0: err = (hostData->Compare(readBuf) == 0) ? KErrNone : KErrCorrupt; sl@0: } sl@0: #else sl@0: *hostData = writeBuf; sl@0: TPtr8 readBuf((TUint8*) writeBuf.Ptr(), writeBuf.Length()); sl@0: err = drive->Read(bOffset, writeBuf.Length(), readBuf, drive->IsWholeMediaAccess()); sl@0: if (err == KErrNone) sl@0: { sl@0: err = (hostData->Compare(readBuf) == 0) ? KErrNone : KErrCorrupt; sl@0: } sl@0: #endif sl@0: sl@0: if (err != KErrNone) sl@0: { sl@0: iSenseInfo.SetSense(TSenseInfo::EMisCompare); sl@0: } sl@0: sl@0: delete hostData; sl@0: } sl@0: else // unknown command sl@0: { sl@0: iSenseInfo.SetSense(TSenseInfo::EAbortedCommand); sl@0: } sl@0: return iSenseInfo.SenseOk() ? KErrNone : KErrAbort; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Command Parser for the MODE SENSE(06) command (0x1A) sl@0: sl@0: @return ETrue if successful. sl@0: */ sl@0: TBool CScsiProtocol::HandleModeSense(TPtrC8& aData, TUint aLun) sl@0: { sl@0: __FNLOG("CScsiProtocol::HandleModeSense"); sl@0: sl@0: TInt pageCode = aData[3] & 0x3F; sl@0: TUint8 pageControl= static_cast(aData[3] >>6); sl@0: sl@0: // reserve 4 bytes for Length, Media type, Device-specific parameter and Block descriptor length sl@0: sl@0: if (pageCode != KAllPages || pageControl == KChangeableValues) sl@0: { sl@0: __PRINT(_L("TSenseInfo::EIllegalRequest,TSenseInfo::EInvalidFieldInCdb")); sl@0: iSenseInfo.SetSense(TSenseInfo::EIllegalRequest,TSenseInfo::EInvalidFieldInCdb); sl@0: return EFalse; sl@0: } sl@0: sl@0: TPtr8 writeBuf(NULL, 0); sl@0: iTransport->GetCommandBufPtr(writeBuf, KModeSenseCommandLength); sl@0: writeBuf.FillZ(KModeSenseCommandLength); sl@0: sl@0: if (pageControl != KDefaultValues) sl@0: { sl@0: //check if drive write protected sl@0: CMassStorageDrive* drive=GetCheckDrive(aLun); sl@0: if (drive == NULL) sl@0: { sl@0: __PRINT(_L("drive == null")); sl@0: return EFalse; sl@0: } sl@0: sl@0: TLocalDriveCapsV4 driveInfo; sl@0: TInt err = drive->Caps(driveInfo); sl@0: if (err != KErrNone) sl@0: { sl@0: __PRINT(_L("TSenseInfo::ENotReady")); sl@0: iSenseInfo.SetSense(TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent); sl@0: return EFalse ; sl@0: } sl@0: sl@0: if (driveInfo.iMediaAtt & KMediaAttWriteProtected) sl@0: { sl@0: writeBuf[2] = 1<<7; // set SWP bit at the Device Specific parameters sl@0: } sl@0: } sl@0: sl@0: writeBuf[0]=3; //Sending only Mode parameter header sl@0: sl@0: TPtrC8 writeBuf1 = writeBuf; sl@0: sl@0: iTransport->SetupWriteData(writeBuf1); sl@0: sl@0: return (iSenseInfo.SenseOk()); sl@0: } sl@0: sl@0: