os/kernelhwsrv/userlibandfileserver/fileserver/shostmassstorage/server/protocol/cscsiprotocol.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     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     // Retry ReadCapacity10L if stalled
   264     TInt stallCounter = 4;
   265     TInt err = KErrNone;
   266     do
   267         {
   268         err = iSbcInterface->ReadCapacity10L(lastLba, blockLength);
   269         } while (err == KErrCommandStalled && stallCounter-- > 0);
   270 
   271 
   272     if (err)
   273         {
   274         if (err == KErrCommandFailed)
   275             {
   276             // Clear sense error
   277             DoCheckConditionL();
   278             }
   279         User::LeaveIfError(KErrAbort);
   280         }
   281 
   282     // update iWriteProtect
   283     err = MsModeSense10L();
   284     if (err)
   285         {
   286         if (err == KErrCommandFailed)
   287             {
   288             // Clear sense error
   289             DoCheckConditionL();
   290             }
   291 
   292         err = MsModeSense6L();
   293         if (err == KErrCommandFailed)
   294             {
   295             // Clear sense error
   296             DoCheckConditionL();
   297             }           
   298         }
   299 
   300     aCapsInfo.iNumberOfBlocks = lastLba + 1;
   301     aCapsInfo.iBlockLength = blockLength;
   302     aCapsInfo.iWriteProtect = iWriteProtect;
   303 
   304 	__SCSIPRINT3(_L("numBlock = x%x , blockLength = %x wp = %d"),
   305                  lastLba + 1, blockLength, iWriteProtect);
   306     }
   307 
   308 
   309 /**
   310 Perform SCSI INQUIRY command. The function leaves if the device response is not
   311 compliant with the protocol standard.
   312 
   313 @return TInt KErrNone if successful otherwise KErrCommandFailed to indicate a
   314 device status error
   315 */
   316 TInt CScsiProtocol::MsInquiryL()
   317     {
   318 	__MSFNLOG
   319     ResetSbc();
   320 
   321    /**
   322     INQUIRY
   323    */
   324 
   325    /**
   326     SPC states
   327     - the INQUIRY data should be returned even though the device server is not
   328       ready for other commands.
   329 
   330     - If the standard INQUIRY data changes for any reason, the device server
   331       shall generate a unit attention condition
   332    */
   333     TPeripheralInfo info;
   334     TInt err = iSpcInterface.InquiryL(info);
   335     if (err)
   336         {
   337         // KErrCommandFailed
   338         return err;
   339         }
   340 
   341     // print reponse
   342     __TESTREPORT1(_L("RMB = %d"), info.iRemovable);
   343     __TESTREPORT2(_L("PERIPHERAL DEVICE TYPE = %d PQ = %d"),
   344                  info.iPeripheralDeviceType,
   345                  info.iPeripheralQualifier);
   346     __TESTREPORT1(_L("VERSION = %d"), info.iVersion);
   347     __TESTREPORT1(_L("RESPONSE DATA FORMAT = %d"), info.iResponseDataFormat);
   348     __TESTREPORT3(_L("VENDOR ID %S PRODUCT ID %S REV %S"),
   349                  &info.iIdentification.iVendorId,
   350                  &info.iIdentification.iProductId,
   351                  &info.iIdentification.iProductRev);
   352 
   353     if (info.iPeripheralQualifier != 0 && info.iPeripheralQualifier != 1)
   354         {
   355         __HOSTPRINT(_L("Peripheral Qualifier[Unknown device type]\n"))
   356         return KErrNotSupported;
   357         }
   358 
   359     if (info.iPeripheralDeviceType != 0)
   360         {
   361         __HOSTPRINT(_L("Peripheral Device Type[Unsupported device type]\n"))
   362         return KErrNotSupported;
   363         }
   364 
   365     iRemovableMedia = info.iRemovable;
   366 
   367     // SCSI Block device
   368     iSbcInterface = new (ELeave) TSbcClientInterface(iSpcInterface.Transport());
   369     iSbcInterface->InitBuffers(&iHeadbuf, &iTailbuf);
   370 
   371     return KErrNone;
   372     }
   373 
   374 
   375 /**
   376 Perform SCSI TEST UNIT READY command. The function leaves if the device response
   377 is not compliant with the protocol standard.
   378 
   379 @return TInt KErrNone if successful or otherwise KErrCommandFailed to indicate a
   380 device status error
   381 */
   382 TInt CScsiProtocol::MsTestUnitReadyL()
   383     {
   384 	__MSFNLOG
   385     /* TestUnitReady */
   386     return iSpcInterface.TestUnitReadyL();
   387     }
   388 
   389 
   390 /**
   391 Perform SCSI READ CAPACITY (10) command. The function leaves if the device
   392 response is not compliant with the protocol standard.
   393 
   394 Before a block device can be read or written the media's capacity (LAST LBA and
   395 BLOCK SIZE) must be obtained. This function is used to initialise TBlockTransfer
   396 with the capacity parameters via TSbcInterface::ReadCapcaityL().
   397 
   398 @return TInt KErrNone if successful, KErrCommandFailed to indicate a
   399 device status error, KErrCommandStalled to indicate a device stall
   400 */
   401 TInt CScsiProtocol::MsReadCapacityL()
   402     {
   403 	__MSFNLOG
   404     // READ CAPACITY
   405     TUint32 blockSize;
   406     TUint32 lastLba;
   407     TInt err = iSbcInterface->ReadCapacity10L(lastLba, blockSize);
   408 
   409     __TESTREPORT2(_L("CAPACITY: Block Size=0x%x Last LBA=0x%x"), blockSize, lastLba);
   410     return err;
   411     }
   412 
   413 
   414 /**
   415 Perform MODE SENSE (10) command. The function leaves if the device response is
   416 not compliant with the protocol standard.
   417 
   418 @return TInt KErrNone if successful, KErrCommandFailed to indicate a
   419 device status error, KErrCommandStalled to indicate a device stall
   420 */
   421 TInt CScsiProtocol::MsModeSense10L()
   422     {
   423 	__MSFNLOG
   424     TBool writeProtected;
   425     TInt err = iSbcInterface->ModeSense10L(TSbcClientInterface::EReturnAllModePages, writeProtected);
   426 
   427     if (!err)
   428         {
   429         iWriteProtect = writeProtected;
   430         }
   431     return err;
   432     }
   433 
   434 
   435 /**
   436 Perform SCSI MODE SENSE (6) command. The function leaves if the device response
   437 is not compliant with the protocol standard.
   438 
   439 @return TInt KErrNone if successful, KErrCommandFailed to indicate a
   440 device status error, KErrCommandStalled to indicate a device stall
   441 */
   442 TInt CScsiProtocol::MsModeSense6L()
   443     {
   444 	__MSFNLOG
   445     TBool writeProtected;
   446     TInt err = iSbcInterface->ModeSense6L(TSbcClientInterface::EReturnAllModePages, writeProtected);
   447 
   448     if (!err)
   449         {
   450         iWriteProtect = writeProtected;
   451         }
   452     return err;
   453     }
   454 
   455 
   456 /**
   457 Perform SCSI START STOP UNIT command. The function leaves if the device response
   458 is not compliant with the protocol standard.
   459 
   460 @return TInt KErrNone if successful otherwise KErrCommandFailed to indicate a
   461 device status error
   462 */
   463 TInt CScsiProtocol::MsStartStopUnitL(TBool aStart)
   464     {
   465 	__MSFNLOG
   466     return iSbcInterface->StartStopUnitL(aStart);
   467     }
   468 
   469 
   470 /**
   471 Perform SCSI PREVENT ALLOW MEDIA REMOVAL command. The function leaves if the
   472 device response is not compliant with the protocol standard.
   473 
   474 @return TInt KErrNone if successful otherwise KErrCommandFailed to indicate a
   475 device status error
   476 */
   477 TInt CScsiProtocol::MsPreventAllowMediaRemovalL(TBool aPrevent)
   478     {
   479 	__MSFNLOG
   480     return iSpcInterface.PreventAllowMediumRemovalL(aPrevent);
   481     }
   482 
   483 
   484 void CScsiProtocol::DoCheckConditionL()
   485     {
   486 	__MSFNLOG
   487     User::LeaveIfError(MsRequestSenseL());
   488 
   489     // Check if init is needed
   490     if (iSenseInfo.iSenseCode == TSenseInfo::ENotReady &&
   491         iSenseInfo.iAdditional == TSenseInfo::EAscLogicalUnitNotReady &&
   492         iSenseInfo.iQualifier == TSenseInfo::EAscqInitializingCommandRequired)
   493         {
   494         // start unit
   495         TInt err = iSbcInterface->StartStopUnitL(ETrue);
   496 
   497         if (err)
   498             {
   499             User::LeaveIfError(MsRequestSenseL());
   500             }
   501 
   502         }
   503 
   504     TInt r = GetSystemWideSenseError(iSenseInfo);
   505 
   506     if (((r == KErrNotReady) && (iState == EConnected)) ||
   507         r == KErrDisconnected)
   508 	    {
   509         CompleteNotifyChangeL();
   510         }
   511     }
   512 
   513 
   514 /**
   515 Map SCSI sense error to a system wide error code
   516 KErrNotReady could happen due to any of the following reasons:
   517     1. Lun is in the process of becoming ready
   518     2. Initialising command is required
   519     3. Lun is not ready to process the command - meaning it is still handling
   520     the previous command
   521 
   522 KErrUnknown could happen due to any of the following reasons:
   523     1. Mass storage device does not respond to the selected logical unit, other
   524     than the locial unit not ready scenario 2. The command sent was not
   525     recognized or contains a invalid code 3. Invialid field in the command block
   526     4. The requested logical unit is not supported
   527     5. The mass storage device cnosists of insufficient resource
   528     6. Hardware error
   529     7. Blank check
   530     8. Vendor specific error
   531     9. Any illegal request (we assume the commands sent by MSC should be
   532     supported by the device, if not then the illegal request is said to be of
   533     unknown system wide error for Symbian. 10. Miscompare - we do not support
   534     the compare operation/command so this error should not happen
   535 
   536 KErrAccessDenied could happen due to any of the following reasons:
   537     1. Data protection error happened
   538     2. Media was write protected
   539     3. Media was not present
   540 
   541 KErrOverflow could happen due to any of the following reasons:
   542     1. Data over flow occured
   543     2. The requested LBA is out of range
   544 
   545 KErrAbort could happen due to any of the following reasons:
   546     1. A copy operation is aborted.
   547     2. The command is aborted
   548 
   549 KErrCorrupt could happen due to any of the following reasons:
   550     1. The underlying media was having errors
   551 
   552 KErrDisconnected could happen due to any of the following reasons:
   553     1. The media was changed/removed - While this error is happening the file
   554     extension will be notified setting the iChanged flag
   555 */
   556 TInt CScsiProtocol::GetSystemWideSenseError(const TSenseInfo& aSenseInfo)
   557 	{
   558 	__MSFNLOG
   559 	TInt ret = KErrNone;
   560 	TInt additionalError = KErrNone;
   561 
   562 	switch(aSenseInfo.iSenseCode)
   563 		{
   564 		case TSenseInfo::ENoSense:
   565 		case TSenseInfo::ERecoveredError:
   566 			ret = KErrNone;
   567 			break;
   568 		case TSenseInfo::ENotReady:
   569             ret = KErrNotReady;
   570 			additionalError = ProcessAsCodes(aSenseInfo);
   571             if (additionalError != KErrNone)
   572                 {
   573                 ret = additionalError;
   574                 }
   575 			break;
   576 		case TSenseInfo::EMediumError:
   577 			ret = KErrCorrupt;
   578 			additionalError = ProcessAsCodes(aSenseInfo);
   579             if (additionalError != KErrNone)
   580                 {
   581                 ret = additionalError;
   582                 }
   583 			break;
   584 		case TSenseInfo::EUnitAttention:
   585 			ret = KErrDisconnected;
   586 			break;
   587 		case TSenseInfo::EDataProtection:
   588 			ret = KErrAccessDenied;
   589 			break;
   590 		case TSenseInfo::EIllegalRequest:
   591 		case TSenseInfo::EHardwareError:
   592 		case TSenseInfo::EBlankCheck:
   593 		case TSenseInfo::EVendorSpecific:
   594 		case TSenseInfo::EMisCompare:
   595 			ret = KErrUnknown;
   596 			break;
   597 		case TSenseInfo::ECopyAborted:
   598 		case TSenseInfo::EAbortedCommand:
   599 			ret = KErrAbort;
   600 			break;
   601 		case TSenseInfo::EDataOverflow:
   602 			ret = KErrOverflow;
   603 			break;
   604 		default:
   605 			ret = KErrUnknown;
   606 			break;
   607 		}
   608 
   609 	return ret;
   610 	}
   611 
   612 
   613 TInt CScsiProtocol::ProcessAsCodes(const TSenseInfo& aSenseInfo)
   614     {
   615 	__MSFNLOG
   616 	TInt ret = KErrNone;
   617 
   618 	switch(aSenseInfo.iAdditional)
   619 		{
   620         case TSenseInfo::EAscLogicalUnitNotReady:
   621 		case TSenseInfo::EMediaNotPresent:
   622             ret = KErrNotReady;
   623 			break;
   624 
   625 		case TSenseInfo::ELbaOutOfRange:
   626 			ret = KErrOverflow;
   627 			break;
   628 
   629 		case TSenseInfo::EWriteProtected:
   630 			ret = KErrAccessDenied;
   631 			break;
   632 
   633 		case TSenseInfo::ENotReadyToReadyChange:
   634 			ret = KErrNone;
   635 			break;
   636 
   637 		case TSenseInfo::EAscLogicalUnitDoesNotRespondToSelection:
   638 		case TSenseInfo::EInvalidCmdCode:
   639 		case TSenseInfo::EInvalidFieldInCdb:
   640 		case TSenseInfo::ELuNotSupported:
   641         case TSenseInfo::EInsufficientRes:
   642             ret = KErrUnknown;
   643             break;
   644 		default:
   645 			ret = KErrNone;
   646 			break;
   647 		}
   648 	return ret;
   649 	}
   650 
   651 
   652 /**
   653 Perform SCSI REQUEST SENSE command.  The function leaves if the device response
   654 is not compliant with the protocol standard.
   655 
   656 @return TInt KErrNone if successful otherwise KErrCommandFailed to indicate a
   657 device status error
   658 */
   659 TInt CScsiProtocol::MsRequestSenseL()
   660     {
   661 	__MSFNLOG
   662     return iSpcInterface.RequestSenseL(iSenseInfo) ? KErrCommandFailed : KErrNone;
   663 	}
   664 
   665 
   666 void CScsiProtocol::CreateSbcInterfaceL(TUint32 aBlockLen, TUint32 aLastLba)
   667     {
   668 	__MSFNLOG
   669     // SCSI Block device
   670     ASSERT(iSbcInterface == NULL);
   671     iSbcInterface = new (ELeave) TSbcClientInterface(iSpcInterface.Transport());
   672     iSbcInterface->InitBuffers(&iHeadbuf, &iTailbuf);
   673     iSbcInterface->SetCapacityL(aBlockLen, aLastLba);
   674     }
   675 
   676 
   677 void CScsiProtocol::ResetSbc()
   678     {
   679 	__MSFNLOG
   680     if (iSbcInterface)
   681         {
   682         delete iSbcInterface;
   683         iSbcInterface = NULL;
   684         }
   685     }
   686 
   687 
   688 void CScsiProtocol::NotifyChange(const RMessage2& aMessage)
   689 	{
   690     __MSFNLOG
   691     iMediaChangeNotifier.Register(aMessage);
   692 	}
   693 
   694 
   695 void CScsiProtocol::ForceCompleteNotifyChangeL()
   696 	{
   697     __MSFNLOG
   698     iMediaChangeNotifier.DoNotifyL();
   699 	}
   700 
   701 
   702 void CScsiProtocol::CancelChangeNotifierL()
   703 	{
   704     __MSFNLOG
   705     iMediaChangeNotifier.DoCancelL();
   706 	}
   707 
   708 
   709 void CScsiProtocol::SuspendL()
   710 	{
   711     __MSFNLOG
   712     if (iFsm->StartStopUnitRequired())
   713         {
   714         iSbcInterface->StartStopUnitL(EFalse);
   715         }
   716 	}
   717 
   718 void CScsiProtocol::ResumeL()
   719 	{
   720     __MSFNLOG
   721     if (iFsm->StartStopUnitRequired())
   722         {
   723         iSbcInterface->StartStopUnitL(ETrue);
   724         }
   725 	}
   726 
   727 
   728 void CScsiProtocol::DoScsiReadyCheckEventL()
   729 	{
   730     __MSFNLOG
   731 	TInt err = KErrNone;
   732 
   733 	if(iFsm->IsRemovableMedia() || iState == EDisconnected)
   734         {
   735 		iFsm->SetStatusCheck();
   736 		TRAP(err, iFsm->ConnectLogicalUnitL());
   737 		iFsm->ClearStatusCheck();
   738 
   739 		User::LeaveIfError(err);
   740 		err = iFsm->IsConnected() ? KErrNone : KErrNotReady;
   741         }
   742 
   743 	if (iState == EConnected)
   744         {
   745 		if (err != KErrNone)
   746 			{
   747 			iState = EDisconnected;
   748             __SCSIPRINT(_L("** Disconnected Notification **"));
   749             iMediaChangeNotifier.DoNotifyL();
   750 			}
   751         }
   752 	else
   753         {
   754 		if (err == KErrNone)
   755 			{
   756 			iState = EConnected;
   757             __SCSIPRINT(_L("** Connected Notification **"));
   758             iMediaChangeNotifier.DoNotifyL();
   759 			}
   760         }
   761 	}
   762 
   763 void CScsiProtocol::CompleteNotifyChangeL()
   764 	{
   765     __MSFNLOG
   766     if (!iFsm->IsStatusCheck())
   767 		{
   768 		if (iState == EConnected)
   769 			{
   770 			iState = EDisconnected;
   771             iMediaChangeNotifier.DoNotifyL();
   772 			}
   773 		}
   774 	}
   775 
   776 RMediaChangeNotifier::RMediaChangeNotifier()
   777 :   iRegistered(EFalse)
   778     {
   779     __MSFNSLOG
   780     }
   781 
   782 
   783 RMediaChangeNotifier::~RMediaChangeNotifier()
   784     {
   785     __MSFNSLOG
   786     if (iRegistered)
   787         iNotifier.Complete(KErrDisconnected);
   788     }
   789 
   790 /**
   791 Initialise notifier to enable media change notfications.
   792 
   793 @param aMessage The message to commplete the notification
   794 */
   795 void RMediaChangeNotifier::Register(const RMessage2& aMessage)
   796     {
   797     __MSFNLOG
   798 	iRegistered = ETrue;
   799 	iNotifier = aMessage;
   800     }
   801 
   802 
   803 void RMediaChangeNotifier::DoNotifyL()
   804     {
   805 	__MSFNLOG
   806 	CompleteNotifierL(KErrNone);
   807     }
   808 
   809 void RMediaChangeNotifier::DoCancelL()
   810     {
   811 	__MSFNLOG
   812 	CompleteNotifierL(KErrCancel);
   813     }
   814 
   815 void RMediaChangeNotifier::CompleteNotifierL(TInt aReason)
   816 	{
   817     __MSFNLOG
   818 	if (iRegistered)
   819         {
   820 		TBool mediaChanged = ETrue;
   821 		TPtrC8 pStatus((TUint8*)&mediaChanged,sizeof(TBool));
   822 		iNotifier.WriteL(0,pStatus);
   823 		iNotifier.Complete(aReason);
   824 		iRegistered = EFalse;
   825         }
   826 	}