os/kernelhwsrv/userlibandfileserver/fileserver/shostmassstorage/server/protocol/cscsiprotocol.cpp
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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
27 #include "msgservice.h"
31 #include "mtransport.h"
32 #include "mprotocol.h"
33 #include "tscsiclientreq.h"
34 #include "tscsiprimarycmds.h"
35 #include "tscsiblockcmds.h"
37 #include "mblocktransferprotocol.h"
38 #include "tblocktransfer.h"
40 #include "tsbcclientinterface.h"
41 #include "tspcclientinterface.h"
42 #include "cmassstoragefsm.h"
43 #include "cscsiprotocol.h"
45 #include "usbmshostpanic.h"
50 Create the CScsiProtocol object.
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
57 CScsiProtocol* CScsiProtocol::NewL(TLun aLun, MTransport& aTransport)
60 CScsiProtocol* r = new (ELeave) CScsiProtocol(aTransport);
62 CleanupStack::PushL(r);
68 void CScsiProtocol::ConstructL(TLun aLun)
71 iFsm = CMassStorageFsm::NewL(*this);
72 iState = EDisconnected;
74 const TInt blockLength = 0x200;
76 iHeadbuf.CreateL(blockLength);
77 iTailbuf.CreateL(blockLength);
81 CScsiProtocol::CScsiProtocol(MTransport& aTransport)
82 : iSpcInterface(aTransport),
89 CScsiProtocol::~CScsiProtocol()
99 void CScsiProtocol::InitialiseUnitL()
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;
109 iFsm->ConnectLogicalUnitL();
110 iState = iFsm->IsConnected() ? EConnected: EDisconnected;
112 if (iState == EConnected)
116 User::After(1000 * 200); // 200 mS
118 while (retryCounter);
122 void CScsiProtocol::UninitialiseUnitL()
125 iFsm->DisconnectLogicalUnitL();
128 TBool CScsiProtocol::IsConnected()
131 return (iState == EConnected)? ETrue : EFalse;
134 void CScsiProtocol::ReadL(TPos aPos,
140 User::Leave(KErrNotReady);
141 iSbcInterface->iBlockTransfer.ReadL(*this, aPos, aLength, aBuf);
145 void CScsiProtocol::BlockReadL(TPos aPos, TDes8& aCopybuf, TInt aLen)
148 __ASSERT_DEBUG(aPos % iSbcInterface->iBlockTransfer.BlockLength() == 0,
149 User::Panic(KUsbMsHostPanicCat, EBlockDevice));
151 const TInt blockLen = iSbcInterface->iBlockTransfer.BlockLength();
154 TInt64 lba = aPos / static_cast<TInt64>(blockLen);
158 User::LeaveIfError(KErrOverflow);
161 TInt err = iSbcInterface->Read10L(I64LOW(lba), aCopybuf, len);
164 __SCSIPRINT1(_L("READ(10) Err=%d"), err);
166 User::LeaveIfError(KErrAbort);
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);
177 // full blocks read in bytes
178 TInt bytesRead = len/blockLen * blockLen;
183 __SCSIPRINT3(_L("New Pos=0x%lx Len=0x%x (bytes read = %x)"),
184 aPos, aLen, bytesRead);
186 aCopybuf.SetLength(bytesRead);
188 // read rest of the block
189 TInt err = iSbcInterface->Read10L(aPos/blockLen, aCopybuf, len);
193 User::LeaveIfError(KErrAbort);
199 void CScsiProtocol::WriteL(TPos aPosition,
205 User::Leave(KErrNotReady);
206 iSbcInterface->iBlockTransfer.WriteL(*this, aPosition, aLength, aBuf);
210 void CScsiProtocol::BlockWriteL(TPos aPos, TDesC8& aCopybuf, TUint aOffset, TInt aLen)
213 __ASSERT_DEBUG(aPos % iSbcInterface->iBlockTransfer.BlockLength() == 0,
214 User::Panic(KUsbMsHostPanicCat, EBlockDevice));
215 const TInt blockLen = iSbcInterface->iBlockTransfer.BlockLength();
217 TInt err = iSbcInterface->Write10L(aPos/blockLen, aCopybuf, aOffset, len);
221 User::LeaveIfError(KErrAbort);
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);
232 // full blocks written in bytes
233 TInt bytesWritten = len/blockLen * blockLen;
234 aPos += bytesWritten;
235 aLen -= bytesWritten;
237 __SCSIPRINT2(_L("New Pos=0x%lx Len=0x%x"), aPos, aLen);
239 TPtrC8 buf = aCopybuf.Mid(bytesWritten);
241 // write rest of the block
242 TInt err = iSbcInterface->Write10L(aPos/blockLen, buf, aOffset, len);
246 User::LeaveIfError(KErrAbort);
252 void CScsiProtocol::GetCapacityL(TCapsInfo& aCapsInfo)
257 DoScsiReadyCheckEventL();
263 // Retry ReadCapacity10L if stalled
264 TInt stallCounter = 4;
268 err = iSbcInterface->ReadCapacity10L(lastLba, blockLength);
269 } while (err == KErrCommandStalled && stallCounter-- > 0);
274 if (err == KErrCommandFailed)
279 User::LeaveIfError(KErrAbort);
282 // update iWriteProtect
283 err = MsModeSense10L();
286 if (err == KErrCommandFailed)
292 err = MsModeSense6L();
293 if (err == KErrCommandFailed)
300 aCapsInfo.iNumberOfBlocks = lastLba + 1;
301 aCapsInfo.iBlockLength = blockLength;
302 aCapsInfo.iWriteProtect = iWriteProtect;
304 __SCSIPRINT3(_L("numBlock = x%x , blockLength = %x wp = %d"),
305 lastLba + 1, blockLength, iWriteProtect);
310 Perform SCSI INQUIRY command. The function leaves if the device response is not
311 compliant with the protocol standard.
313 @return TInt KErrNone if successful otherwise KErrCommandFailed to indicate a
316 TInt CScsiProtocol::MsInquiryL()
327 - the INQUIRY data should be returned even though the device server is not
328 ready for other commands.
330 - If the standard INQUIRY data changes for any reason, the device server
331 shall generate a unit attention condition
333 TPeripheralInfo info;
334 TInt err = iSpcInterface.InquiryL(info);
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);
353 if (info.iPeripheralQualifier != 0 && info.iPeripheralQualifier != 1)
355 __HOSTPRINT(_L("Peripheral Qualifier[Unknown device type]\n"))
356 return KErrNotSupported;
359 if (info.iPeripheralDeviceType != 0)
361 __HOSTPRINT(_L("Peripheral Device Type[Unsupported device type]\n"))
362 return KErrNotSupported;
365 iRemovableMedia = info.iRemovable;
368 iSbcInterface = new (ELeave) TSbcClientInterface(iSpcInterface.Transport());
369 iSbcInterface->InitBuffers(&iHeadbuf, &iTailbuf);
376 Perform SCSI TEST UNIT READY command. The function leaves if the device response
377 is not compliant with the protocol standard.
379 @return TInt KErrNone if successful or otherwise KErrCommandFailed to indicate a
382 TInt CScsiProtocol::MsTestUnitReadyL()
386 return iSpcInterface.TestUnitReadyL();
391 Perform SCSI READ CAPACITY (10) command. The function leaves if the device
392 response is not compliant with the protocol standard.
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().
398 @return TInt KErrNone if successful, KErrCommandFailed to indicate a
399 device status error, KErrCommandStalled to indicate a device stall
401 TInt CScsiProtocol::MsReadCapacityL()
407 TInt err = iSbcInterface->ReadCapacity10L(lastLba, blockSize);
409 __TESTREPORT2(_L("CAPACITY: Block Size=0x%x Last LBA=0x%x"), blockSize, lastLba);
415 Perform MODE SENSE (10) command. The function leaves if the device response is
416 not compliant with the protocol standard.
418 @return TInt KErrNone if successful, KErrCommandFailed to indicate a
419 device status error, KErrCommandStalled to indicate a device stall
421 TInt CScsiProtocol::MsModeSense10L()
424 TBool writeProtected;
425 TInt err = iSbcInterface->ModeSense10L(TSbcClientInterface::EReturnAllModePages, writeProtected);
429 iWriteProtect = writeProtected;
436 Perform SCSI MODE SENSE (6) command. The function leaves if the device response
437 is not compliant with the protocol standard.
439 @return TInt KErrNone if successful, KErrCommandFailed to indicate a
440 device status error, KErrCommandStalled to indicate a device stall
442 TInt CScsiProtocol::MsModeSense6L()
445 TBool writeProtected;
446 TInt err = iSbcInterface->ModeSense6L(TSbcClientInterface::EReturnAllModePages, writeProtected);
450 iWriteProtect = writeProtected;
457 Perform SCSI START STOP UNIT command. The function leaves if the device response
458 is not compliant with the protocol standard.
460 @return TInt KErrNone if successful otherwise KErrCommandFailed to indicate a
463 TInt CScsiProtocol::MsStartStopUnitL(TBool aStart)
466 return iSbcInterface->StartStopUnitL(aStart);
471 Perform SCSI PREVENT ALLOW MEDIA REMOVAL command. The function leaves if the
472 device response is not compliant with the protocol standard.
474 @return TInt KErrNone if successful otherwise KErrCommandFailed to indicate a
477 TInt CScsiProtocol::MsPreventAllowMediaRemovalL(TBool aPrevent)
480 return iSpcInterface.PreventAllowMediumRemovalL(aPrevent);
484 void CScsiProtocol::DoCheckConditionL()
487 User::LeaveIfError(MsRequestSenseL());
489 // Check if init is needed
490 if (iSenseInfo.iSenseCode == TSenseInfo::ENotReady &&
491 iSenseInfo.iAdditional == TSenseInfo::EAscLogicalUnitNotReady &&
492 iSenseInfo.iQualifier == TSenseInfo::EAscqInitializingCommandRequired)
495 TInt err = iSbcInterface->StartStopUnitL(ETrue);
499 User::LeaveIfError(MsRequestSenseL());
504 TInt r = GetSystemWideSenseError(iSenseInfo);
506 if (((r == KErrNotReady) && (iState == EConnected)) ||
507 r == KErrDisconnected)
509 CompleteNotifyChangeL();
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
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
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
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
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
545 KErrAbort could happen due to any of the following reasons:
546 1. A copy operation is aborted.
547 2. The command is aborted
549 KErrCorrupt could happen due to any of the following reasons:
550 1. The underlying media was having errors
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
556 TInt CScsiProtocol::GetSystemWideSenseError(const TSenseInfo& aSenseInfo)
560 TInt additionalError = KErrNone;
562 switch(aSenseInfo.iSenseCode)
564 case TSenseInfo::ENoSense:
565 case TSenseInfo::ERecoveredError:
568 case TSenseInfo::ENotReady:
570 additionalError = ProcessAsCodes(aSenseInfo);
571 if (additionalError != KErrNone)
573 ret = additionalError;
576 case TSenseInfo::EMediumError:
578 additionalError = ProcessAsCodes(aSenseInfo);
579 if (additionalError != KErrNone)
581 ret = additionalError;
584 case TSenseInfo::EUnitAttention:
585 ret = KErrDisconnected;
587 case TSenseInfo::EDataProtection:
588 ret = KErrAccessDenied;
590 case TSenseInfo::EIllegalRequest:
591 case TSenseInfo::EHardwareError:
592 case TSenseInfo::EBlankCheck:
593 case TSenseInfo::EVendorSpecific:
594 case TSenseInfo::EMisCompare:
597 case TSenseInfo::ECopyAborted:
598 case TSenseInfo::EAbortedCommand:
601 case TSenseInfo::EDataOverflow:
613 TInt CScsiProtocol::ProcessAsCodes(const TSenseInfo& aSenseInfo)
618 switch(aSenseInfo.iAdditional)
620 case TSenseInfo::EAscLogicalUnitNotReady:
621 case TSenseInfo::EMediaNotPresent:
625 case TSenseInfo::ELbaOutOfRange:
629 case TSenseInfo::EWriteProtected:
630 ret = KErrAccessDenied;
633 case TSenseInfo::ENotReadyToReadyChange:
637 case TSenseInfo::EAscLogicalUnitDoesNotRespondToSelection:
638 case TSenseInfo::EInvalidCmdCode:
639 case TSenseInfo::EInvalidFieldInCdb:
640 case TSenseInfo::ELuNotSupported:
641 case TSenseInfo::EInsufficientRes:
653 Perform SCSI REQUEST SENSE command. The function leaves if the device response
654 is not compliant with the protocol standard.
656 @return TInt KErrNone if successful otherwise KErrCommandFailed to indicate a
659 TInt CScsiProtocol::MsRequestSenseL()
662 return iSpcInterface.RequestSenseL(iSenseInfo) ? KErrCommandFailed : KErrNone;
666 void CScsiProtocol::CreateSbcInterfaceL(TUint32 aBlockLen, TUint32 aLastLba)
670 ASSERT(iSbcInterface == NULL);
671 iSbcInterface = new (ELeave) TSbcClientInterface(iSpcInterface.Transport());
672 iSbcInterface->InitBuffers(&iHeadbuf, &iTailbuf);
673 iSbcInterface->SetCapacityL(aBlockLen, aLastLba);
677 void CScsiProtocol::ResetSbc()
682 delete iSbcInterface;
683 iSbcInterface = NULL;
688 void CScsiProtocol::NotifyChange(const RMessage2& aMessage)
691 iMediaChangeNotifier.Register(aMessage);
695 void CScsiProtocol::ForceCompleteNotifyChangeL()
698 iMediaChangeNotifier.DoNotifyL();
702 void CScsiProtocol::CancelChangeNotifierL()
705 iMediaChangeNotifier.DoCancelL();
709 void CScsiProtocol::SuspendL()
712 if (iFsm->StartStopUnitRequired())
714 iSbcInterface->StartStopUnitL(EFalse);
718 void CScsiProtocol::ResumeL()
721 if (iFsm->StartStopUnitRequired())
723 iSbcInterface->StartStopUnitL(ETrue);
728 void CScsiProtocol::DoScsiReadyCheckEventL()
733 if(iFsm->IsRemovableMedia() || iState == EDisconnected)
735 iFsm->SetStatusCheck();
736 TRAP(err, iFsm->ConnectLogicalUnitL());
737 iFsm->ClearStatusCheck();
739 User::LeaveIfError(err);
740 err = iFsm->IsConnected() ? KErrNone : KErrNotReady;
743 if (iState == EConnected)
747 iState = EDisconnected;
748 __SCSIPRINT(_L("** Disconnected Notification **"));
749 iMediaChangeNotifier.DoNotifyL();
757 __SCSIPRINT(_L("** Connected Notification **"));
758 iMediaChangeNotifier.DoNotifyL();
763 void CScsiProtocol::CompleteNotifyChangeL()
766 if (!iFsm->IsStatusCheck())
768 if (iState == EConnected)
770 iState = EDisconnected;
771 iMediaChangeNotifier.DoNotifyL();
776 RMediaChangeNotifier::RMediaChangeNotifier()
777 : iRegistered(EFalse)
783 RMediaChangeNotifier::~RMediaChangeNotifier()
787 iNotifier.Complete(KErrDisconnected);
791 Initialise notifier to enable media change notfications.
793 @param aMessage The message to commplete the notification
795 void RMediaChangeNotifier::Register(const RMessage2& aMessage)
799 iNotifier = aMessage;
803 void RMediaChangeNotifier::DoNotifyL()
806 CompleteNotifierL(KErrNone);
809 void RMediaChangeNotifier::DoCancelL()
812 CompleteNotifierL(KErrCancel);
815 void RMediaChangeNotifier::CompleteNotifierL(TInt aReason)
820 TBool mediaChanged = ETrue;
821 TPtrC8 pStatus((TUint8*)&mediaChanged,sizeof(TBool));
822 iNotifier.WriteL(0,pStatus);
823 iNotifier.Complete(aReason);
824 iRegistered = EFalse;