userlibandfileserver/fileserver/shostmassstorage/server/protocol/cscsiprotocol.cpp
changeset 43 96e5fb8b040d
child 44 36bfc973b146
equal deleted inserted replaced
-1:000000000000 43:96e5fb8b040d
       
     1 // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of the License "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 /**
       
    17  @file
       
    18  @internalTechnology
       
    19 */
       
    20 
       
    21 #include <e32base.h>
       
    22 
       
    23 #include "debug.h"
       
    24 #include "msdebug.h"
       
    25 #include "msctypes.h"
       
    26 #include "shared.h"
       
    27 #include "msgservice.h"
       
    28 
       
    29 #include "mscutils.h"
       
    30 
       
    31 #include "mtransport.h"
       
    32 #include "mprotocol.h"
       
    33 #include "tscsiclientreq.h"
       
    34 #include "tscsiprimarycmds.h"
       
    35 #include "tscsiblockcmds.h"
       
    36 
       
    37 #include "mblocktransferprotocol.h"
       
    38 #include "tblocktransfer.h"
       
    39 
       
    40 #include "tsbcclientinterface.h"
       
    41 #include "tspcclientinterface.h"
       
    42 #include "cmassstoragefsm.h"
       
    43 #include "cscsiprotocol.h"
       
    44 
       
    45 #include "usbmshostpanic.h"
       
    46 
       
    47 
       
    48 
       
    49 /**
       
    50 Create the CScsiProtocol object.
       
    51 
       
    52 @param aLun The LUN for the device represented by this object
       
    53 @param aTransport The transport interface
       
    54 @param aStatusPollingInterval The polling interval
       
    55 @return CScsiProtocol* A reference to the
       
    56 */
       
    57 CScsiProtocol* CScsiProtocol::NewL(TLun aLun, MTransport& aTransport)
       
    58     {
       
    59 	__MSFNSLOG
       
    60 	CScsiProtocol* r = new (ELeave) CScsiProtocol(aTransport);
       
    61 
       
    62 	CleanupStack::PushL(r);
       
    63 	r->ConstructL(aLun);
       
    64 	CleanupStack::Pop();
       
    65 	return r;
       
    66     }
       
    67 
       
    68 void CScsiProtocol::ConstructL(TLun aLun)
       
    69     {
       
    70 	__MSFNLOG
       
    71     iFsm = CMassStorageFsm::NewL(*this);
       
    72 	iState = EDisconnected;
       
    73 
       
    74     const TInt blockLength = 0x200;
       
    75 
       
    76     iHeadbuf.CreateL(blockLength);
       
    77     iTailbuf.CreateL(blockLength);
       
    78     }
       
    79 
       
    80 
       
    81 CScsiProtocol::CScsiProtocol(MTransport& aTransport)
       
    82 :   iSpcInterface(aTransport),
       
    83     iSbcInterface(NULL)
       
    84     {
       
    85 	__MSFNLOG
       
    86     }
       
    87 
       
    88 
       
    89 CScsiProtocol::~CScsiProtocol()
       
    90     {
       
    91 	__MSFNLOG
       
    92     delete iFsm;
       
    93     iHeadbuf.Close();
       
    94     iTailbuf.Close();
       
    95     delete iSbcInterface;
       
    96     }
       
    97 
       
    98 
       
    99 void CScsiProtocol::InitialiseUnitL()
       
   100     {
       
   101 	__MSFNLOG
       
   102 
       
   103 	// A device may take time to mount the media. If the device fails attempt to
       
   104 	// retry the connection for a number of seconds
       
   105     TInt retryCounter = 20;
       
   106     do
       
   107         {
       
   108         retryCounter--;
       
   109         iFsm->ConnectLogicalUnitL();
       
   110         iState = iFsm->IsConnected() ? EConnected: EDisconnected;
       
   111 
       
   112         if (iState == EConnected)
       
   113             {
       
   114             break;
       
   115             }
       
   116         User::After(1000 * 200);    // 200 mS
       
   117         }
       
   118     while (retryCounter);
       
   119 	}
       
   120 
       
   121 
       
   122 void CScsiProtocol::UninitialiseUnitL()
       
   123     {
       
   124 	__MSFNLOG
       
   125     iFsm->DisconnectLogicalUnitL();
       
   126     }
       
   127 
       
   128 TBool CScsiProtocol::IsConnected()
       
   129     {
       
   130 	__MSFNLOG
       
   131 	return (iState == EConnected)? ETrue : EFalse;
       
   132     }
       
   133 
       
   134 void CScsiProtocol::ReadL(TPos aPos,
       
   135                           TDes8& aBuf,
       
   136                           TInt aLength)
       
   137     {
       
   138 	__MSFNLOG
       
   139     if(!IsConnected())
       
   140 		User::Leave(KErrNotReady);
       
   141     iSbcInterface->iBlockTransfer.ReadL(*this, aPos, aLength, aBuf);
       
   142     }
       
   143 
       
   144 
       
   145 void CScsiProtocol::BlockReadL(TPos aPos, TDes8& aCopybuf, TInt aLen)
       
   146     {
       
   147 	__MSFNLOG
       
   148 	__ASSERT_DEBUG(aPos % iSbcInterface->iBlockTransfer.BlockLength() == 0,
       
   149                    User::Panic(KUsbMsHostPanicCat, EBlockDevice));
       
   150 
       
   151     const TInt blockLen = iSbcInterface->iBlockTransfer.BlockLength();
       
   152     TInt len = aLen;
       
   153 
       
   154     TInt64 lba = aPos / static_cast<TInt64>(blockLen);
       
   155 
       
   156     if (I64HIGH(lba))
       
   157         {
       
   158         User::LeaveIfError(KErrOverflow);
       
   159         }
       
   160 
       
   161 	TInt err = iSbcInterface->Read10L(I64LOW(lba), aCopybuf, len);
       
   162     if (err)
       
   163         {
       
   164         __SCSIPRINT1(_L("READ(10) Err=%d"), err);
       
   165         DoCheckConditionL();
       
   166         User::LeaveIfError(KErrAbort);
       
   167         }
       
   168 
       
   169     // handle residue
       
   170     while (len != aLen)
       
   171         {
       
   172         __SCSIPRINT2(_L("SCSI Read Residue 0x%x bytes read (0x%x)"), len, aLen);
       
   173         __SCSIPRINT2(_L("Pos=0x%lx Len=0x%x"), aPos, aLen);
       
   174 
       
   175         // read next block
       
   176 
       
   177         // full blocks read in bytes
       
   178         TInt bytesRead = len/blockLen * blockLen;
       
   179         aPos += bytesRead;
       
   180         aLen -= bytesRead;
       
   181         len = aLen;
       
   182 
       
   183         __SCSIPRINT3(_L("New Pos=0x%lx Len=0x%x (bytes read = %x)"),
       
   184                      aPos, aLen, bytesRead);
       
   185 
       
   186         aCopybuf.SetLength(bytesRead);
       
   187 
       
   188         // read rest of the block
       
   189         TInt err = iSbcInterface->Read10L(aPos/blockLen, aCopybuf, len);
       
   190         if (err)
       
   191             {
       
   192             DoCheckConditionL();
       
   193             User::LeaveIfError(KErrAbort);
       
   194             }
       
   195         }
       
   196     }
       
   197 
       
   198 
       
   199 void CScsiProtocol::WriteL(TPos aPosition,
       
   200                            TDesC8& aBuf,
       
   201                            TInt aLength)
       
   202     {
       
   203 	__MSFNLOG
       
   204     if(!IsConnected())
       
   205 		User::Leave(KErrNotReady);
       
   206     iSbcInterface->iBlockTransfer.WriteL(*this, aPosition, aLength, aBuf);
       
   207     }
       
   208 
       
   209 
       
   210 void CScsiProtocol::BlockWriteL(TPos aPos, TDesC8& aCopybuf, TUint aOffset, TInt aLen)
       
   211     {
       
   212 	__MSFNLOG
       
   213 	__ASSERT_DEBUG(aPos % iSbcInterface->iBlockTransfer.BlockLength() == 0,
       
   214                    User::Panic(KUsbMsHostPanicCat, EBlockDevice));
       
   215     const TInt blockLen = iSbcInterface->iBlockTransfer.BlockLength();
       
   216     TInt len = aLen;
       
   217 	TInt err = iSbcInterface->Write10L(aPos/blockLen, aCopybuf, aOffset, len);
       
   218     if (err)
       
   219         {
       
   220         DoCheckConditionL();
       
   221         User::LeaveIfError(KErrAbort);
       
   222         }
       
   223 
       
   224     while (len != aLen)
       
   225         {
       
   226         // handle residue
       
   227         __SCSIPRINT2(_L("SCSI Write Residue 0x%x bytes read (0x%x)"), len, aLen);
       
   228         __SCSIPRINT2(_L("Pos=0x%lx Len=0x%x"), aPos, aLen);
       
   229 
       
   230         // write next block
       
   231 
       
   232         // full blocks written in bytes
       
   233         TInt bytesWritten = len/blockLen * blockLen;
       
   234         aPos += bytesWritten;
       
   235         aLen -= bytesWritten;
       
   236         len = aLen;
       
   237         __SCSIPRINT2(_L("New Pos=0x%lx Len=0x%x"), aPos, aLen);
       
   238 
       
   239         TPtrC8 buf = aCopybuf.Mid(bytesWritten);
       
   240 
       
   241         // write rest of the block
       
   242         TInt err = iSbcInterface->Write10L(aPos/blockLen, buf, aOffset, len);
       
   243         if (err)
       
   244             {
       
   245             DoCheckConditionL();
       
   246             User::LeaveIfError(KErrAbort);
       
   247             }
       
   248         }
       
   249     }
       
   250 
       
   251 
       
   252 void CScsiProtocol::GetCapacityL(TCapsInfo& aCapsInfo)
       
   253     {
       
   254 	__MSFNLOG
       
   255     if (!IsConnected())
       
   256         {
       
   257         DoScsiReadyCheckEventL();
       
   258         }
       
   259 
       
   260 	TLba lastLba;
       
   261 	TUint32 blockLength;
       
   262 
       
   263 	TInt err = iSbcInterface->ReadCapacity10L(lastLba, blockLength);
       
   264     if (err)
       
   265         {
       
   266         if (err == KErrCommandFailed)
       
   267             {
       
   268             // Clear sense error
       
   269             DoCheckConditionL();
       
   270             }
       
   271         User::LeaveIfError(KErrAbort);
       
   272         }
       
   273 
       
   274     // update iWriteProtect
       
   275     err = MsModeSense10L();
       
   276     if (err)
       
   277         {
       
   278         if (err == KErrCommandFailed)
       
   279             {
       
   280             // Clear sense error
       
   281             DoCheckConditionL();
       
   282             }
       
   283 
       
   284         err = MsModeSense6L();
       
   285         if (err == KErrCommandFailed)
       
   286             {
       
   287             // Clear sense error
       
   288             DoCheckConditionL();
       
   289             }           
       
   290         }
       
   291 
       
   292     aCapsInfo.iNumberOfBlocks = lastLba + 1;
       
   293     aCapsInfo.iBlockLength = blockLength;
       
   294     aCapsInfo.iWriteProtect = iWriteProtect;
       
   295 
       
   296 	__SCSIPRINT3(_L("numBlock = x%x , blockLength = %x wp = %d"),
       
   297                  lastLba + 1, blockLength, iWriteProtect);
       
   298     }
       
   299 
       
   300 
       
   301 /**
       
   302 Perform SCSI INQUIRY command. The function leaves if the device response is not
       
   303 compliant with the protocol standard.
       
   304 
       
   305 @return TInt KErrNone if successful otherwise KErrCommandFailed to indicate a
       
   306 device status error
       
   307 */
       
   308 TInt CScsiProtocol::MsInquiryL()
       
   309     {
       
   310 	__MSFNLOG
       
   311     ResetSbc();
       
   312 
       
   313    /**
       
   314     INQUIRY
       
   315    */
       
   316 
       
   317    /**
       
   318     SPC states
       
   319     - the INQUIRY data should be returned even though the device server is not
       
   320       ready for other commands.
       
   321 
       
   322     - If the standard INQUIRY data changes for any reason, the device server
       
   323       shall generate a unit attention condition
       
   324    */
       
   325     TPeripheralInfo info;
       
   326     TInt err = iSpcInterface.InquiryL(info);
       
   327     if (err)
       
   328         {
       
   329         // KErrCommandFailed
       
   330         return err;
       
   331         }
       
   332 
       
   333     // print reponse
       
   334     __TESTREPORT1(_L("RMB = %d"), info.iRemovable);
       
   335     __TESTREPORT2(_L("PERIPHERAL DEVICE TYPE = %d PQ = %d"),
       
   336                  info.iPeripheralDeviceType,
       
   337                  info.iPeripheralQualifier);
       
   338     __TESTREPORT1(_L("VERSION = %d"), info.iVersion);
       
   339     __TESTREPORT1(_L("RESPONSE DATA FORMAT = %d"), info.iResponseDataFormat);
       
   340     __TESTREPORT3(_L("VENDOR ID %S PRODUCT ID %S REV %S"),
       
   341                  &info.iIdentification.iVendorId,
       
   342                  &info.iIdentification.iProductId,
       
   343                  &info.iIdentification.iProductRev);
       
   344 
       
   345     if (info.iPeripheralQualifier != 0 && info.iPeripheralQualifier != 1)
       
   346         {
       
   347         __HOSTPRINT(_L("Peripheral Qualifier[Unknown device type]\n"))
       
   348         return KErrNotSupported;
       
   349         }
       
   350 
       
   351     if (info.iPeripheralDeviceType != 0)
       
   352         {
       
   353         __HOSTPRINT(_L("Peripheral Device Type[Unsupported device type]\n"))
       
   354         return KErrNotSupported;
       
   355         }
       
   356 
       
   357     iRemovableMedia = info.iRemovable;
       
   358 
       
   359     // SCSI Block device
       
   360     iSbcInterface = new (ELeave) TSbcClientInterface(iSpcInterface.Transport());
       
   361     iSbcInterface->InitBuffers(&iHeadbuf, &iTailbuf);
       
   362 
       
   363     return KErrNone;
       
   364     }
       
   365 
       
   366 
       
   367 /**
       
   368 Perform SCSI TEST UNIT READY command. The function leaves if the device response
       
   369 is not compliant with the protocol standard.
       
   370 
       
   371 @return TInt KErrNone if successful or otherwise KErrCommandFailed to indicate a
       
   372 device status error
       
   373 */
       
   374 TInt CScsiProtocol::MsTestUnitReadyL()
       
   375     {
       
   376 	__MSFNLOG
       
   377     /* TestUnitReady */
       
   378     return iSpcInterface.TestUnitReadyL();
       
   379     }
       
   380 
       
   381 
       
   382 /**
       
   383 Perform SCSI READ CAPACITY (10) command. The function leaves if the device
       
   384 response is not compliant with the protocol standard.
       
   385 
       
   386 Before a block device can be read or written the media's capacity (LAST LBA and
       
   387 BLOCK SIZE) must be obtained. This function is used to initialise TBlockTransfer
       
   388 with the capacity parameters via TSbcInterface::ReadCapcaityL().
       
   389 
       
   390 @return TInt KErrNone if successful, KErrCommandFailed to indicate a
       
   391 device status error, KErrCommandStalled to indicate a device stall
       
   392 */
       
   393 TInt CScsiProtocol::MsReadCapacityL()
       
   394     {
       
   395 	__MSFNLOG
       
   396     // READ CAPACITY
       
   397     TUint32 blockSize;
       
   398     TUint32 lastLba;
       
   399     TInt err = iSbcInterface->ReadCapacity10L(lastLba, blockSize);
       
   400 
       
   401     __TESTREPORT2(_L("CAPACITY: Block Size=0x%x Last LBA=0x%x"), blockSize, lastLba);
       
   402     return err;
       
   403     }
       
   404 
       
   405 
       
   406 /**
       
   407 Perform MODE SENSE (10) command. The function leaves if the device response is
       
   408 not compliant with the protocol standard.
       
   409 
       
   410 @return TInt KErrNone if successful, KErrCommandFailed to indicate a
       
   411 device status error, KErrCommandStalled to indicate a device stall
       
   412 */
       
   413 TInt CScsiProtocol::MsModeSense10L()
       
   414     {
       
   415 	__MSFNLOG
       
   416     TBool writeProtected;
       
   417     TInt err = iSbcInterface->ModeSense10L(TSbcClientInterface::EReturnAllModePages, writeProtected);
       
   418 
       
   419     if (!err)
       
   420         {
       
   421         iWriteProtect = writeProtected;
       
   422         }
       
   423     return err;
       
   424     }
       
   425 
       
   426 
       
   427 /**
       
   428 Perform SCSI MODE SENSE (6) command. The function leaves if the device response
       
   429 is not compliant with the protocol standard.
       
   430 
       
   431 @return TInt KErrNone if successful, KErrCommandFailed to indicate a
       
   432 device status error, KErrCommandStalled to indicate a device stall
       
   433 */
       
   434 TInt CScsiProtocol::MsModeSense6L()
       
   435     {
       
   436 	__MSFNLOG
       
   437     TBool writeProtected;
       
   438     TInt err = iSbcInterface->ModeSense6L(TSbcClientInterface::EReturnAllModePages, writeProtected);
       
   439 
       
   440     if (!err)
       
   441         {
       
   442         iWriteProtect = writeProtected;
       
   443         }
       
   444     return err;
       
   445     }
       
   446 
       
   447 
       
   448 /**
       
   449 Perform SCSI START STOP UNIT command. The function leaves if the device response
       
   450 is not compliant with the protocol standard.
       
   451 
       
   452 @return TInt KErrNone if successful otherwise KErrCommandFailed to indicate a
       
   453 device status error
       
   454 */
       
   455 TInt CScsiProtocol::MsStartStopUnitL(TBool aStart)
       
   456     {
       
   457 	__MSFNLOG
       
   458     return iSbcInterface->StartStopUnitL(aStart);
       
   459     }
       
   460 
       
   461 
       
   462 /**
       
   463 Perform SCSI PREVENT ALLOW MEDIA REMOVAL command. The function leaves if the
       
   464 device response is not compliant with the protocol standard.
       
   465 
       
   466 @return TInt KErrNone if successful otherwise KErrCommandFailed to indicate a
       
   467 device status error
       
   468 */
       
   469 TInt CScsiProtocol::MsPreventAllowMediaRemovalL(TBool aPrevent)
       
   470     {
       
   471 	__MSFNLOG
       
   472     return iSpcInterface.PreventAllowMediumRemovalL(aPrevent);
       
   473     }
       
   474 
       
   475 
       
   476 void CScsiProtocol::DoCheckConditionL()
       
   477     {
       
   478 	__MSFNLOG
       
   479     User::LeaveIfError(MsRequestSenseL());
       
   480 
       
   481     // Check if init is needed
       
   482     if (iSenseInfo.iSenseCode == TSenseInfo::ENotReady &&
       
   483         iSenseInfo.iAdditional == TSenseInfo::EAscLogicalUnitNotReady &&
       
   484         iSenseInfo.iQualifier == TSenseInfo::EAscqInitializingCommandRequired)
       
   485         {
       
   486         // start unit
       
   487         TInt err = iSbcInterface->StartStopUnitL(ETrue);
       
   488 
       
   489         if (err)
       
   490             {
       
   491             User::LeaveIfError(MsRequestSenseL());
       
   492             }
       
   493 
       
   494         }
       
   495 
       
   496     TInt r = GetSystemWideSenseError(iSenseInfo);
       
   497 
       
   498     if (((r == KErrNotReady) && (iState == EConnected)) ||
       
   499         r == KErrDisconnected)
       
   500 	    {
       
   501         CompleteNotifyChangeL();
       
   502         }
       
   503     }
       
   504 
       
   505 
       
   506 /**
       
   507 Map SCSI sense error to a system wide error code
       
   508 KErrNotReady could happen due to any of the following reasons:
       
   509     1. Lun is in the process of becoming ready
       
   510     2. Initialising command is required
       
   511     3. Lun is not ready to process the command - meaning it is still handling
       
   512     the previous command
       
   513 
       
   514 KErrUnknown could happen due to any of the following reasons:
       
   515     1. Mass storage device does not respond to the selected logical unit, other
       
   516     than the locial unit not ready scenario 2. The command sent was not
       
   517     recognized or contains a invalid code 3. Invialid field in the command block
       
   518     4. The requested logical unit is not supported
       
   519     5. The mass storage device cnosists of insufficient resource
       
   520     6. Hardware error
       
   521     7. Blank check
       
   522     8. Vendor specific error
       
   523     9. Any illegal request (we assume the commands sent by MSC should be
       
   524     supported by the device, if not then the illegal request is said to be of
       
   525     unknown system wide error for Symbian. 10. Miscompare - we do not support
       
   526     the compare operation/command so this error should not happen
       
   527 
       
   528 KErrAccessDenied could happen due to any of the following reasons:
       
   529     1. Data protection error happened
       
   530     2. Media was write protected
       
   531     3. Media was not present
       
   532 
       
   533 KErrOverflow could happen due to any of the following reasons:
       
   534     1. Data over flow occured
       
   535     2. The requested LBA is out of range
       
   536 
       
   537 KErrAbort could happen due to any of the following reasons:
       
   538     1. A copy operation is aborted.
       
   539     2. The command is aborted
       
   540 
       
   541 KErrCorrupt could happen due to any of the following reasons:
       
   542     1. The underlying media was having errors
       
   543 
       
   544 KErrDisconnected could happen due to any of the following reasons:
       
   545     1. The media was changed/removed - While this error is happening the file
       
   546     extension will be notified setting the iChanged flag
       
   547 */
       
   548 TInt CScsiProtocol::GetSystemWideSenseError(const TSenseInfo& aSenseInfo)
       
   549 	{
       
   550 	__MSFNLOG
       
   551 	TInt ret = KErrNone;
       
   552 	TInt additionalError = KErrNone;
       
   553 
       
   554 	switch(aSenseInfo.iSenseCode)
       
   555 		{
       
   556 		case TSenseInfo::ENoSense:
       
   557 		case TSenseInfo::ERecoveredError:
       
   558 			ret = KErrNone;
       
   559 			break;
       
   560 		case TSenseInfo::ENotReady:
       
   561             ret = KErrNotReady;
       
   562 			additionalError = ProcessAsCodes(aSenseInfo);
       
   563             if (additionalError != KErrNone)
       
   564                 {
       
   565                 ret = additionalError;
       
   566                 }
       
   567 			break;
       
   568 		case TSenseInfo::EMediumError:
       
   569 			ret = KErrCorrupt;
       
   570 			additionalError = ProcessAsCodes(aSenseInfo);
       
   571             if (additionalError != KErrNone)
       
   572                 {
       
   573                 ret = additionalError;
       
   574                 }
       
   575 			break;
       
   576 		case TSenseInfo::EUnitAttention:
       
   577 			ret = KErrDisconnected;
       
   578 			break;
       
   579 		case TSenseInfo::EDataProtection:
       
   580 			ret = KErrAccessDenied;
       
   581 			break;
       
   582 		case TSenseInfo::EIllegalRequest:
       
   583 		case TSenseInfo::EHardwareError:
       
   584 		case TSenseInfo::EBlankCheck:
       
   585 		case TSenseInfo::EVendorSpecific:
       
   586 		case TSenseInfo::EMisCompare:
       
   587 			ret = KErrUnknown;
       
   588 			break;
       
   589 		case TSenseInfo::ECopyAborted:
       
   590 		case TSenseInfo::EAbortedCommand:
       
   591 			ret = KErrAbort;
       
   592 			break;
       
   593 		case TSenseInfo::EDataOverflow:
       
   594 			ret = KErrOverflow;
       
   595 			break;
       
   596 		default:
       
   597 			ret = KErrUnknown;
       
   598 			break;
       
   599 		}
       
   600 
       
   601 	return ret;
       
   602 	}
       
   603 
       
   604 
       
   605 TInt CScsiProtocol::ProcessAsCodes(const TSenseInfo& aSenseInfo)
       
   606     {
       
   607 	__MSFNLOG
       
   608 	TInt ret = KErrNone;
       
   609 
       
   610 	switch(aSenseInfo.iAdditional)
       
   611 		{
       
   612         case TSenseInfo::EAscLogicalUnitNotReady:
       
   613 		case TSenseInfo::EMediaNotPresent:
       
   614             ret = KErrNotReady;
       
   615 			break;
       
   616 
       
   617 		case TSenseInfo::ELbaOutOfRange:
       
   618 			ret = KErrOverflow;
       
   619 			break;
       
   620 
       
   621 		case TSenseInfo::EWriteProtected:
       
   622 			ret = KErrAccessDenied;
       
   623 			break;
       
   624 
       
   625 		case TSenseInfo::ENotReadyToReadyChange:
       
   626 			ret = KErrNone;
       
   627 			break;
       
   628 
       
   629 		case TSenseInfo::EAscLogicalUnitDoesNotRespondToSelection:
       
   630 		case TSenseInfo::EInvalidCmdCode:
       
   631 		case TSenseInfo::EInvalidFieldInCdb:
       
   632 		case TSenseInfo::ELuNotSupported:
       
   633         case TSenseInfo::EInsufficientRes:
       
   634             ret = KErrUnknown;
       
   635             break;
       
   636 		default:
       
   637 			ret = KErrNone;
       
   638 			break;
       
   639 		}
       
   640 	return ret;
       
   641 	}
       
   642 
       
   643 
       
   644 /**
       
   645 Perform SCSI REQUEST SENSE command.  The function leaves if the device response
       
   646 is not compliant with the protocol standard.
       
   647 
       
   648 @return TInt KErrNone if successful otherwise KErrCommandFailed to indicate a
       
   649 device status error
       
   650 */
       
   651 TInt CScsiProtocol::MsRequestSenseL()
       
   652     {
       
   653 	__MSFNLOG
       
   654     return iSpcInterface.RequestSenseL(iSenseInfo) ? KErrCommandFailed : KErrNone;
       
   655 	}
       
   656 
       
   657 
       
   658 void CScsiProtocol::CreateSbcInterfaceL(TUint32 aBlockLen, TUint32 aLastLba)
       
   659     {
       
   660 	__MSFNLOG
       
   661     // SCSI Block device
       
   662     ASSERT(iSbcInterface == NULL);
       
   663     iSbcInterface = new (ELeave) TSbcClientInterface(iSpcInterface.Transport());
       
   664     iSbcInterface->InitBuffers(&iHeadbuf, &iTailbuf);
       
   665     iSbcInterface->SetCapacityL(aBlockLen, aLastLba);
       
   666     }
       
   667 
       
   668 
       
   669 void CScsiProtocol::ResetSbc()
       
   670     {
       
   671 	__MSFNLOG
       
   672     if (iSbcInterface)
       
   673         {
       
   674         delete iSbcInterface;
       
   675         iSbcInterface = NULL;
       
   676         }
       
   677     }
       
   678 
       
   679 
       
   680 void CScsiProtocol::NotifyChange(const RMessage2& aMessage)
       
   681 	{
       
   682     __MSFNLOG
       
   683     iMediaChangeNotifier.Register(aMessage);
       
   684 	}
       
   685 
       
   686 
       
   687 void CScsiProtocol::ForceCompleteNotifyChangeL()
       
   688 	{
       
   689     __MSFNLOG
       
   690     iMediaChangeNotifier.DoNotifyL();
       
   691 	}
       
   692 
       
   693 
       
   694 void CScsiProtocol::CancelChangeNotifierL()
       
   695 	{
       
   696     __MSFNLOG
       
   697     iMediaChangeNotifier.DoCancelL();
       
   698 	}
       
   699 
       
   700 
       
   701 void CScsiProtocol::SuspendL()
       
   702 	{
       
   703     __MSFNLOG
       
   704     if (iFsm->StartStopUnitRequired())
       
   705         {
       
   706         iSbcInterface->StartStopUnitL(EFalse);
       
   707         }
       
   708 	}
       
   709 
       
   710 void CScsiProtocol::ResumeL()
       
   711 	{
       
   712     __MSFNLOG
       
   713     if (iFsm->StartStopUnitRequired())
       
   714         {
       
   715         iSbcInterface->StartStopUnitL(ETrue);
       
   716         }
       
   717 	}
       
   718 
       
   719 
       
   720 void CScsiProtocol::DoScsiReadyCheckEventL()
       
   721 	{
       
   722     __MSFNLOG
       
   723 	TInt err = KErrNone;
       
   724 
       
   725 	if(iFsm->IsRemovableMedia() || iState == EDisconnected)
       
   726         {
       
   727 		iFsm->SetStatusCheck();
       
   728 		TRAP(err, iFsm->ConnectLogicalUnitL());
       
   729 		iFsm->ClearStatusCheck();
       
   730 
       
   731 		User::LeaveIfError(err);
       
   732 		err = iFsm->IsConnected() ? KErrNone : KErrNotReady;
       
   733         }
       
   734 
       
   735 	if (iState == EConnected)
       
   736         {
       
   737 		if (err != KErrNone)
       
   738 			{
       
   739 			iState = EDisconnected;
       
   740             __SCSIPRINT(_L("** Disconnected Notification **"));
       
   741             iMediaChangeNotifier.DoNotifyL();
       
   742 			}
       
   743         }
       
   744 	else
       
   745         {
       
   746 		if (err == KErrNone)
       
   747 			{
       
   748 			iState = EConnected;
       
   749             __SCSIPRINT(_L("** Connected Notification **"));
       
   750             iMediaChangeNotifier.DoNotifyL();
       
   751 			}
       
   752         }
       
   753 	}
       
   754 
       
   755 void CScsiProtocol::CompleteNotifyChangeL()
       
   756 	{
       
   757     __MSFNLOG
       
   758     if (!iFsm->IsStatusCheck())
       
   759 		{
       
   760 		if (iState == EConnected)
       
   761 			{
       
   762 			iState = EDisconnected;
       
   763             iMediaChangeNotifier.DoNotifyL();
       
   764 			}
       
   765 		}
       
   766 	}
       
   767 
       
   768 RMediaChangeNotifier::RMediaChangeNotifier()
       
   769 :   iRegistered(EFalse)
       
   770     {
       
   771     __MSFNSLOG
       
   772     }
       
   773 
       
   774 
       
   775 RMediaChangeNotifier::~RMediaChangeNotifier()
       
   776     {
       
   777     __MSFNSLOG
       
   778     if (iRegistered)
       
   779         iNotifier.Complete(KErrDisconnected);
       
   780     }
       
   781 
       
   782 /**
       
   783 Initialise notifier to enable media change notfications.
       
   784 
       
   785 @param aMessage The message to commplete the notification
       
   786 */
       
   787 void RMediaChangeNotifier::Register(const RMessage2& aMessage)
       
   788     {
       
   789     __MSFNLOG
       
   790 	iRegistered = ETrue;
       
   791 	iNotifier = aMessage;
       
   792     }
       
   793 
       
   794 
       
   795 void RMediaChangeNotifier::DoNotifyL()
       
   796     {
       
   797 	__MSFNLOG
       
   798 	CompleteNotifierL(KErrNone);
       
   799     }
       
   800 
       
   801 void RMediaChangeNotifier::DoCancelL()
       
   802     {
       
   803 	__MSFNLOG
       
   804 	CompleteNotifierL(KErrCancel);
       
   805     }
       
   806 
       
   807 void RMediaChangeNotifier::CompleteNotifierL(TInt aReason)
       
   808 	{
       
   809     __MSFNLOG
       
   810 	if (iRegistered)
       
   811         {
       
   812 		TBool mediaChanged = ETrue;
       
   813 		TPtrC8 pStatus((TUint8*)&mediaChanged,sizeof(TBool));
       
   814 		iNotifier.WriteL(0,pStatus);
       
   815 		iNotifier.Complete(aReason);
       
   816 		iRegistered = EFalse;
       
   817         }
       
   818 	}