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