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 "msdebug.h" sl@0: #include "debug.h" sl@0: #include "msctypes.h" sl@0: sl@0: #include "mtransport.h" sl@0: #include "mprotocol.h" sl@0: #include "tscsiclientreq.h" sl@0: sl@0: #include "tblocktransfer.h" sl@0: #include "mscutils.h" sl@0: #include "usbmshostpanic.h" sl@0: #include "tscsiblockcmds.h" sl@0: #include "tsbcclientinterface.h" sl@0: sl@0: /** sl@0: Constructor. sl@0: sl@0: @param aTransport The Transport interface to be used sl@0: */ sl@0: TSbcClientInterface::TSbcClientInterface(MTransport& aTransport) sl@0: : iTransport(aTransport) sl@0: { sl@0: __MSFNLOG sl@0: } sl@0: sl@0: sl@0: TSbcClientInterface::~TSbcClientInterface() sl@0: { sl@0: __MSFNLOG sl@0: } sl@0: sl@0: sl@0: /** sl@0: Constructor to create and send SCSI MODE SENSE (6) request to obtain the sl@0: medium's Write Protect status. The function leaves if the device response is not sl@0: compliant with the protocol standard. sl@0: sl@0: @param aPageCode The SCSI PAGE CODE value sl@0: @param aWriteProtected The SCSI WP value sl@0: sl@0: @return TInt KErrNone if successful, KErrCommandFailed to indicate a sl@0: device status error, KErrCommandStalled to indicate device stall sl@0: */ sl@0: TInt TSbcClientInterface::ModeSense6L(TUint aPageCode, TBool& aWriteProtected) sl@0: { sl@0: __MSFNLOG sl@0: TScsiClientModeSense6Req modeSense6Req(TScsiClientModeSense6Req::ECurrentValues, sl@0: aPageCode); sl@0: TScsiClientModeSense6Resp modeSense6Resp; sl@0: TInt err = iTransport.SendControlCmdL(&modeSense6Req, &modeSense6Resp); sl@0: if (!err) sl@0: { sl@0: __SCSIPRINT1(_L("SCSI MODE SENSE (6) INFO WrProtect=%d"), sl@0: modeSense6Resp.iWriteProtected); sl@0: aWriteProtected = modeSense6Resp.iWriteProtected; sl@0: } sl@0: else sl@0: { sl@0: aWriteProtected = EFalse; sl@0: } sl@0: return err; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Create and send SCSI MODE SENSE (10) request to obtain the mediums Write Protect sl@0: status. The function leaves if the device response is not compliant with the sl@0: protocol standard. sl@0: sl@0: @param aPageCode The SCSI PAGE CODE value sl@0: @param aWriteProtected The SCSI WP value 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 TSbcClientInterface::ModeSense10L(TUint aPageCode, TBool& aWriteProtected) sl@0: { sl@0: __MSFNLOG sl@0: TScsiClientModeSense10Req modeSense10Req(TScsiClientModeSense10Req::ECurrentValues, sl@0: aPageCode); sl@0: TScsiClientModeSense10Resp modeSense10Resp; sl@0: TInt err = iTransport.SendControlCmdL(&modeSense10Req, &modeSense10Resp); sl@0: sl@0: if (!err) sl@0: { sl@0: __SCSIPRINT1(_L("SCSI MODE SENSE (10) INFO WrProtect=%d"), sl@0: modeSense10Resp.iWriteProtected); sl@0: aWriteProtected = modeSense10Resp.iWriteProtected; sl@0: } sl@0: else sl@0: { sl@0: aWriteProtected = EFalse; sl@0: } sl@0: return err; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Constructor to create SCSI MODE SENSE (10) request. sl@0: sl@0: @param aPageControl The SCSI PAGE CODE value sl@0: @param aPageCode The SCSI WP value sl@0: @param aSubPageCode The SCSI SUB PAGE CODE value sl@0: */ sl@0: TScsiClientModeSense10Req::TScsiClientModeSense10Req(TPageControl aPageControl, sl@0: TUint aPageCode, sl@0: TUint aSubPageCode) sl@0: : sl@0: TScsiClientReq(EModeSense10), sl@0: iPageControl(aPageControl), sl@0: iPageCode(aPageCode), sl@0: iSubPageCode(aSubPageCode), sl@0: iAllocationLength(KResponseLength) sl@0: { sl@0: __MSFNLOG sl@0: } sl@0: sl@0: sl@0: TInt TScsiClientModeSense10Req::EncodeRequestL(TDes8& aBuffer) const sl@0: { sl@0: __MSFNSLOG sl@0: __SCSIPRINT(_L("<-- SCSI MODE SENSE (10)")); sl@0: TInt length = TScsiClientReq::EncodeRequestL(aBuffer); sl@0: sl@0: // PC sl@0: aBuffer[2] = iPageCode; sl@0: aBuffer[2] |= iPageControl << 6; sl@0: aBuffer[3] = iSubPageCode; sl@0: sl@0: BigEndian::Put16(&aBuffer[7], iAllocationLength); sl@0: return length; sl@0: } sl@0: sl@0: /** sl@0: Create READ (10) request and send to the transport layer. This performs a sl@0: logical block read of the device server. The received data is appended into the sl@0: copy buffer. The function leaves if the device response is not compliant with sl@0: the protocol standard. sl@0: Note that TBlockTransfer must be initialised beforehand. sl@0: sl@0: @param aLba The Logical Block address to read from sl@0: @param aBuffer The buffer to copy data to sl@0: @param aLen The number of bytes to be read (IN) and returns the number of bytes sl@0: actually read (OUT) sl@0: sl@0: @return TInt KErrNone if successful otherwise KErrCommandFailed to indicate a sl@0: device status error or KErrArgument to indicate that aLen is too large for the sl@0: protocol. sl@0: */ sl@0: TInt TSbcClientInterface::Read10L(TLba aLba, TDes8& aBuffer, TInt& aLen) sl@0: { sl@0: __MSFNLOG sl@0: __ASSERT_DEBUG(iBlockTransfer.BlockLength(), User::Panic(KUsbMsHostPanicCat, EBlockLengthNotSet)); sl@0: __ASSERT_DEBUG(aLen % iBlockTransfer.BlockLength() == 0, User::Panic(KUsbMsHostPanicCat, EBlockDevice)); sl@0: sl@0: TScsiClientRead10Req read10Req; sl@0: sl@0: read10Req.iLogicalBlockAddress = aLba; sl@0: sl@0: TInt blockTransferLength = aLen / iBlockTransfer.BlockLength(); sl@0: if (blockTransferLength > static_cast(KMaxTUint16)) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: read10Req.iBlockTransferLength = static_cast(blockTransferLength); sl@0: TInt err = iTransport.SendDataRxCmdL(&read10Req, aBuffer, aLen); sl@0: return err; sl@0: } sl@0: sl@0: /** sl@0: Create READ CAPACITY (10) request and send to the transport layer. The request sl@0: returns the device servers capacity information. The device server's response sl@0: values are also used here to initialise the TBlockTransfer values. The function sl@0: leaves if the device response is not compliant with the protocol standard. sl@0: sl@0: @param aLba The Logical Block Address returned by the LU sl@0: @param aBlockSize The Block Size returned by the LU 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 TSbcClientInterface::ReadCapacity10L(TLba& aLba, TUint32& aBlockSize) sl@0: { sl@0: __MSFNLOG sl@0: TScsiClientReadCapacity10Req capacity10Req; sl@0: TScsiClientReadCapacity10Resp capacity10Resp; sl@0: sl@0: TInt err = iTransport.SendControlCmdL(&capacity10Req, &capacity10Resp); sl@0: if (!err) sl@0: { sl@0: aLba = capacity10Resp.iLba; sl@0: aBlockSize = capacity10Resp.iBlockSize; sl@0: sl@0: __SCSIPRINT2(_L("Capacity LBA=0x%08x SIZE=0x%08x"), sl@0: aLba, aBlockSize); sl@0: sl@0: iBlockTransfer.SetCapacityL(aBlockSize, aLba); sl@0: } sl@0: return err; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Create START STOP UNIT request. The function leaves if the device response is sl@0: not compliant with the protocol standard. sl@0: sl@0: @param aStart SCSI START value sl@0: sl@0: @return TInt KErrNone if successful otherwise KErrCommandFailed to indicate a sl@0: device status error sl@0: */ sl@0: TInt TSbcClientInterface::StartStopUnitL(TBool aStart) sl@0: { sl@0: __MSFNLOG sl@0: TScsiClientStartStopUnitReq startStopUnitReq; sl@0: sl@0: startStopUnitReq.iImmed = ETrue; sl@0: startStopUnitReq.iLoej = EFalse; sl@0: startStopUnitReq.iStart = aStart; sl@0: sl@0: TInt err = iTransport.SendControlCmdL(&startStopUnitReq); sl@0: sl@0: return err; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Create WRITE (10) request and send to the transport layer. This performs a sl@0: logical block write of the device server. Note that TBlockTransfer must be sl@0: initialised beforehand. The function leaves if the device response is not sl@0: compliant with the protocol standard. sl@0: sl@0: @param aLba Logical Block Address to write the data to sl@0: @param aBuffer Buffer containing the data sl@0: @param aPos Offset into the buffer to the data sl@0: @param aLen The number of bytes to be written (IN) and returns the bytes sl@0: actually transferred (OUT) sl@0: sl@0: @return TInt KErrNone if successful otherwise KErrCommandFailed to indicate a sl@0: device status error or KErrArgument to indicate that aLen is too large for the sl@0: protocol. sl@0: */ sl@0: TInt TSbcClientInterface::Write10L(TLba aLba, TDesC8& aBuffer, TUint aPos, TInt& aLen) sl@0: { sl@0: __MSFNLOG sl@0: __ASSERT_DEBUG(iBlockTransfer.BlockLength(), User::Panic(KUsbMsHostPanicCat, EBlockLengthNotSet)); sl@0: __ASSERT_DEBUG(aLen % iBlockTransfer.BlockLength() == 0, User::Panic(KUsbMsHostPanicCat, EBlockDevice)); sl@0: sl@0: // check that buffer size is large enough sl@0: if (aBuffer.Length() < (aPos + aLen)) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: sl@0: TScsiClientWrite10Req write10Req; sl@0: write10Req.iLogicalBlockAddress = aLba; sl@0: sl@0: TInt blockTransferLength = aLen / iBlockTransfer.BlockLength(); sl@0: if (blockTransferLength > static_cast(KMaxTUint16)) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: write10Req.iBlockTransferLength = static_cast(blockTransferLength); sl@0: sl@0: TInt err = iTransport.SendDataTxCmdL(&write10Req, aBuffer, aPos, aLen); sl@0: return err; sl@0: } sl@0: