First public contribution.
1 // Copyright (c) 2004-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.
17 #ifdef MSDC_MULTITHREADED
18 #include "rwdrivethread.h"
19 #endif // MSDC_MULTITHREADED
20 #include "massstoragedebug.h"
23 #define LBA(x) static_cast<TUint32>((x[3] << 24) | (x[4] << 16) | (x[5] << 8) | x[6])
24 #define LEN(x) static_cast<TUint16>((x[8] << 8) | x[9])
27 LOCAL_D const TUint KDefaultBlockSize = 0x200; //default block size for FAT
29 LOCAL_D const TUint KUndefinedLun = 0xFFFF;
31 LOCAL_D const TUint8 KAllPages = 0x3F;
33 LOCAL_D const TUint8 KChangeableValues = 0x1;
34 LOCAL_D const TUint8 KDefaultValues = 0x2;
37 Default constructor for TSenseInfo
39 TSenseInfo::TSenseInfo()
40 : iSenseCode(ENoSense),
41 iAdditional(EAscNull),
47 Set sense with no additional info.
49 @param aSenseCode sense key
51 void TSenseInfo::SetSense(TSenseCode aSenseCode)
53 iSenseCode = static_cast<TUint8>(aSenseCode);
54 iAdditional = EAscNull;
55 iQualifier = EAscqNull;
60 Set sense with additional info.
62 @param aSenseCode sense key
63 @param aAdditional additional sense code (ASC)
65 void TSenseInfo::SetSense(TSenseCode aSenseCode, TAdditionalCode aAdditional)
68 iSenseCode = static_cast<TUint8>(aSenseCode);
69 iAdditional = static_cast<TUint8>(aAdditional);
70 iQualifier = EAscqNull;
75 Set sense with additional info and qualifier.
77 @param aSenseCode sense key
78 @param aAdditional additional sense code (ASC)
79 @param aQualifier additional sense code qualifier (ASCQ)
81 void TSenseInfo::SetSense(TSenseCode aSenseCode,
82 TAdditionalCode aAdditional,
83 TAdditionalSenseCodeQualifier aQualifier)
85 iSenseCode = static_cast<TUint8>(aSenseCode);
86 iAdditional = static_cast<TUint8>(aAdditional);
87 iQualifier = static_cast<TUint8>(aQualifier);
91 //-----------------------------------------------
94 Creates the CScsiProtocol object. Called during controller initialisation.
96 @param aDriveManager reference to the drive manager object
98 CScsiProtocol* CScsiProtocol::NewL(CDriveManager& aDriveManager)
100 CScsiProtocol* self = new (ELeave) CScsiProtocol(aDriveManager);
101 CleanupStack::PushL(self);
110 @param aDriveManager reference to the drive manager object
112 CScsiProtocol::CScsiProtocol(CDriveManager& aDriveManager):
113 iDriveManager(aDriveManager),
114 iLastCommand(EUndefinedCommand),
115 iLastLun(KUndefinedLun),
116 iMediaWriteSize(KDefaultMediaWriteSize)
118 __FNLOG("CScsiProtocol::CScsiProtocol");
120 #ifdef USB_TRANSFER_PUBLISHER
121 iWriteTransferPublisher = CUsbWriteTransferPublisher::NewL(iBytesWritten);
122 iReadTransferPublisher = CUsbReadTransferPublisher::NewL(iBytesRead);
124 for (TUint i = 0; i < KUsbMsMaxDrives; i++)
127 iBytesWritten[i] = 0;
130 iWriteTransferPublisher = CDriveWriteTransferPublisher::NewL(aDriveManager.iDrives);
131 iReadTransferPublisher = CDriveReadTransferPublisher::NewL(aDriveManager.iDrives);
136 CScsiProtocol::~CScsiProtocol()
138 __FNLOG("CScsiProtocol::~CScsiProtocol");
139 #ifdef MSDC_MULTITHREADED
140 __PRINT(_L("Deleting WriteDrive Thread"));
141 delete iWriteDriveThread;
142 __PRINT(_L("Deleting ReadDrive Thread"));
143 delete iReadDriveThread;
144 #endif // MSDC_MULTITHREADED
146 delete iWriteTransferPublisher;
147 delete iReadTransferPublisher;
151 void CScsiProtocol::ConstructL()
153 __FNLOG("CScsiProtocol::ConstructL");
154 #ifdef MSDC_MULTITHREADED
155 __PRINT(_L("Creating WriteDrive Thread"));
156 iWriteDriveThread = CWriteDriveThread::NewL();
157 __PRINT(_L("Creating ReadDrive Thread"));
158 iReadDriveThread = CReadDriveThread::NewL();
159 #endif // MSDC_MULTITHREADED
164 Associates the transport with the protocol. Called during initialisation of the controller.
166 @param aTransport pointer to the transport object
168 void CScsiProtocol::RegisterTransport(MTransportBase* aTransport)
170 __FNLOG("CScsiProtocol::RegisterTransport");
171 iTransport = aTransport;
176 Called by the Transport when it detects that the USB device is either running
177 at High Speed or is at least capable of HS operation. The Protocol can use this
178 information (for instance) to select the optimal write block size to use.
180 This function is preferably called before actual MS data transfer operation
181 starts, and usually only once.
184 void CScsiProtocol::ReportHighSpeedDevice()
186 __FNLOG("CScsiProtocol::ReportHighSpeedDevice");
187 iMediaWriteSize = KHsMediaWriteSize;
188 __PRINT1(_L("HS Device reported: SCSI will use %d bytes disk write size"), iMediaWriteSize);
192 TInt CScsiProtocol::SetScsiParameters(TMassStorageConfig aConfig)
194 __FNLOG("CScsiProtocol::SetScsiParameters");
199 #ifdef MSDC_MULTITHREADED
201 void CScsiProtocol::ProcessWriteComplete (TUint8* aAddress, TAny* aPtr)
203 ((CScsiProtocol*)aPtr)->iTransport->ProcessReadData(aAddress);
206 void CScsiProtocol::InitializeBufferPointers(TPtr8& aDes1, TPtr8& aDes2) // Todo Change name later - InitializeReadBufferSomething
208 iReadDriveThread->iThreadContext->iBuffer.SetUpReadBuf(aDes1, aDes2);
213 Called by the transport layer when a packet is available for decoding.
214 If an error occurs, the sense code is updated and EFalse is returned.
218 @return ETrue if command was decoded and executed successfully
220 TBool CScsiProtocol::DecodePacket(TPtrC8& aData, TUint aLun)
222 __FNLOG("CScsiProtocol::DecodePacket");
224 TUint8 command = aData[1];
226 if (command != ERequestSense)
228 iSenseInfo.SetSense(TSenseInfo::ENoSense);
231 __PRINT2(_L("command = 0x%x lun=%d"), command, aLun);
235 HandleUnitReady(aLun);
239 HandleRequestSense(aData);
243 HandleInquiry(aData, aLun);
247 HandleModeSense(aData, aLun);
251 HandleStartStopUnit(aData, aLun);
254 case EPreventMediaRemoval:
255 HandlePreventMediaRemoval(aData, aLun);
259 HandleReadCapacity(aData, aLun);
263 HandleRead10(aData, aLun);
267 HandleWrite10(aData,aLun);
271 HandleVerify10(aData, aLun);
274 case EReadFormatCapacities:
275 HandleReadFormatCapacities(aLun);
279 iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidCmdCode);
281 __PRINT1(_L("DecodePacket result = %d"), iSenseInfo.SenseOk());
282 return(iSenseInfo.SenseOk());
287 Checks if drive ready
289 @param aLun Logic unit number
290 @return pointer to drive correspondent to LUN if drive mounted and ready, NULL otherwise
292 CMassStorageDrive* CScsiProtocol::GetCheckDrive(TUint aLun)
294 __FNLOG("CScsiProtocol::GetCheckDrive");
297 #ifdef MSDC_MULTITHREADED
298 // check for deferred errors
299 if (iWriteDriveThread->DeferredError())
301 iWriteDriveThread->ClearDeferredError();
302 iDeferredSenseInfo.SetSense(TSenseInfo::EMediumError);
308 CMassStorageDrive* drive= iDriveManager.Drive(aLun, err);
310 if (err !=KErrNone || drive == NULL)
312 __PRINT(_L("No drive available\n"));
313 iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::ELuNotSupported);
317 CMassStorageDrive::TMountState mountState = drive->MountState();
319 if (mountState == CMassStorageDrive::EDisconnected || mountState == CMassStorageDrive::EConnecting)
321 __PRINT(_L("Drive disconnected\n"));
322 iSenseInfo.SetSense(TSenseInfo::ENotReady,
323 TSenseInfo::EMediaNotPresent);
327 CMassStorageDrive::TDriveState state = drive->CheckDriveState();
328 if (state == CMassStorageDrive::EMediaNotPresent || state == CMassStorageDrive::ELocked)
330 __PRINT1(_L("Media not present or locked. (state =0x%X)\n"),state);
331 iSenseInfo.SetSense(TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent);
335 if (drive->IsMediaChanged(ETrue)) //reset "media changed" status
337 __PRINT(_L("Media was changed\n"));
338 // SAM-2 Section 5.9.5 Unit Attention Condition
339 iSenseInfo.SetSense(TSenseInfo::EUnitAttention, TSenseInfo::ENotReadyToReadyChange);
340 iDriveManager.Connect(aLun); //publish event to USB app
344 if (mountState == CMassStorageDrive::EDisconnecting)
346 __PRINT(_L("Drive disconnecting\n"));
347 iSenseInfo.SetSense(TSenseInfo::ENotReady,
348 TSenseInfo::EMediaNotPresent);
357 Command Parser for the UNIT READY command (0x00)
359 @param aLun Logic unit number
360 @return ETrue if successful,
362 TBool CScsiProtocol::HandleUnitReady(TUint aLun)
364 __FNLOG("CScsiProtocol::HandleUnitReady");
365 #ifdef MSDC_MULTITHREADED
366 iWriteDriveThread->WaitForWriteEmpty();
368 return GetCheckDrive(aLun) ? (TBool)ETrue : (TBool)EFalse;
373 Command Parser for the REQUEST SENSE command (0x03)
375 @return ETrue if successful,
377 TBool CScsiProtocol::HandleRequestSense(TPtrC8& aData)
379 __FNLOG("CScsiProtocol::HandleRequestSense");
380 TUint length = aData[5];
381 __PRINT1(_L("length = %d\n"), length);
383 TPtr8 writeBuf(NULL, 0);
384 iTransport->GetCommandBufPtr(writeBuf, KRequestSenseCommandLength);
385 writeBuf.FillZ(KRequestSenseCommandLength);
387 TSenseInfo* senseInfo;
388 #ifdef MSDC_MULTITHREADED
389 if (!iDeferredSenseInfo.SenseOk())
391 writeBuf[00] = 0x71; //(deferred errors)
392 senseInfo = &iDeferredSenseInfo;
396 writeBuf[00] = 0x70; //(current errors)
397 senseInfo = &iSenseInfo;
400 senseInfo = &iSenseInfo;
401 writeBuf[00] = 0x70; //(current errors)
404 writeBuf[02] = static_cast<TUint8>(senseInfo->iSenseCode & 0x0F);
406 writeBuf[12] = senseInfo->iAdditional;
407 writeBuf[13] = senseInfo->iQualifier;
408 if (length<18 && length >=8)
410 writeBuf.SetLength(length); //length of response code data
411 writeBuf[07] = TUint8(length - 8); //additional sence length
413 else if (length >= KRequestSenseCommandLength)
415 writeBuf[07] = KRequestSenseCommandLength - 8; // we have max 18 byte to send
418 __PRINT4(_L("Response=0x%x Sense=0x%x, Additional=0x%x, Qualifier=0x%x\n"),
419 writeBuf[0], writeBuf[02], writeBuf[12], writeBuf[13]);
421 TPtrC8 writeBuf1 = writeBuf.Left(length);
423 iTransport->SetupWriteData(writeBuf1);
425 // clear the sense info
426 iSenseInfo.SetSense(TSenseInfo::ENoSense);
428 #ifdef MSDC_MULTITHREADED
429 iDeferredSenseInfo.SetSense(TSenseInfo::ENoSense);
437 Command Parser for the INQUIRY command (0x12)
439 @param aLun Logic unit number
440 @return ETrue if successful,
442 TBool CScsiProtocol::HandleInquiry(TPtrC8& aData, TUint aLun )
444 __FNLOG("CScsiProtocol::HandleInquiry");
446 TBool cmdDt = aData[2] & 0x2;
447 TBool evpd = aData[2] & 0x1;
448 TUint8 page = aData[3];
449 if (cmdDt || evpd || page || aLun >= KUsbMsMaxDrives)
451 iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
455 TPtr8 writeBuf(NULL, 0);
456 iTransport->GetCommandBufPtr(writeBuf, KInquiryCommandLength);
457 writeBuf.FillZ(KInquiryCommandLength);
459 writeBuf[1] = 0x80; // MSB: RMB : Removable
460 writeBuf[3] = 0x02; // AERC, TrmTsk, NormACA, Response Data Format
461 writeBuf[4] = 0x1F; // Additional Length
463 TPtr8 vendorId(&writeBuf[8], 8, 8); // Vendor ID (Vendor Specific/Logged by T10)
464 vendorId.Fill(' ', 8);
465 vendorId.Copy(iConfig.iVendorId);
467 TPtr8 productId(&writeBuf[16], 16, 16); // Product ID (Vendor Specific)
468 productId.Fill(' ', 16);
469 productId.Copy(iConfig.iProductId);
471 TPtr8 productRev(&writeBuf[32], 4, 4); // Product Revision Level (Vendor Specific)
472 productRev.Fill(' ', 4);
473 productRev.Copy(iConfig.iProductRev);
475 TUint length = aData[5];
477 TPtrC8 writeBuf1 = writeBuf.Left(length);
478 iTransport->SetupWriteData(writeBuf1);
480 iSenseInfo.SetSense(TSenseInfo::ENoSense);
486 Command Parser for the START STOP UNIT command (0x1B)
488 @param aData command data (started form position 1)
489 @param aLun Logic unit number
490 @return ETrue if successful, TFalse otherwise
492 TBool CScsiProtocol::HandleStartStopUnit(TPtrC8& aData, TUint aLun)
494 __FNLOG("CScsiProtocol::HandleStartStopUnit");
496 const TUint8 KStartMask = 0x01;
497 const TUint8 KImmedMask = 0x01;
498 const TUint8 KLoejMask = 0x02;
500 TBool immed = aData[2] & KImmedMask ? (TBool)ETrue : (TBool)EFalse;
501 TBool start = aData[5] & KStartMask ? (TBool)ETrue : (TBool)EFalse;
502 TBool loej = aData[5] & KLoejMask ? (TBool)ETrue : (TBool)EFalse;
504 __PRINT2(_L("Data %X %X\n"), aData[2], aData[5]);
505 __PRINT1(_L("IMMED = %d\n"), immed);
506 __PRINT1(_L("START = %d\n"), start);
508 __PRINT1(_L("LOEJ = %d\n"), loej);
513 if(start) //Start unit
515 err = iDriveManager.Connect(aLun);
516 __PRINT(_L("Load media\n"));
518 #ifdef USB_TRANSFER_PUBLISHER
519 iBytesRead[aLun] = 0;
520 iBytesWritten[aLun] = 0;
522 // publish the initial values
523 iWriteTransferPublisher->DoPublishDataTransferredEvent();
524 iReadTransferPublisher->DoPublishDataTransferredEvent();
528 iDriveManager.SetCritical(aLun, EFalse);
529 err = iDriveManager.Disconnect(aLun);
530 __PRINT(_L("Unload media\n"));
534 if (err !=KErrNone) //actually we have error here only if the LUN is incorrect
536 iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::ELuNotSupported);
544 CMassStorageDrive* drive= iDriveManager.Drive(aLun, err);
546 if (err !=KErrNone || drive == NULL)
548 iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::ELuNotSupported);
552 TInt timeLeft (20); // 1 sec timeout
553 CMassStorageDrive::TMountState mountState;
557 User::After(1000 * 50); // 50 mSec
559 mountState = drive->MountState();
561 if ((!start && mountState != CMassStorageDrive::EConnected)
564 (mountState == CMassStorageDrive::EDisconnecting ||
565 mountState == CMassStorageDrive::EConnected))
570 } while (timeLeft>0);
573 iSenseInfo.SetSense(TSenseInfo::ENotReady,
574 TSenseInfo::EAscLogicalUnitDoesNotRespondToSelection);
580 Command Parser for the PREVENT/ALLOW MEDIA REMOVAL command (0x1E)
582 @param aData command data (started form position 1)
583 @param aLun Logic unit number
584 @return ETrue if successful.
586 TBool CScsiProtocol::HandlePreventMediaRemoval(TPtrC8& aData, TUint aLun)
588 __FNLOG("CScsiProtocol::HandlePreventMediaRemoval");
589 CMassStorageDrive* drive=GetCheckDrive(aLun);
596 TInt prevent = aData[5] & 0x01;
597 __PRINT1(_L("prevent = %d\n"), prevent);
598 iDriveManager.SetCritical(aLun, prevent);
604 /** Cancel active state, Invoked by transnport when it stops */
605 TInt CScsiProtocol::Cancel()
607 iDriveManager.SetCritical(CDriveManager::KAllLuns, EFalse);
612 TBool CScsiProtocol::HandleReadFormatCapacities(TUint aLun)
614 * Command Parser for the READ FORMAT CAPACITIES command (0x23)
616 * @return ETrue if successful, else a standard Symbian OS error code.
619 __FNLOG("CScsiProtocol::HandleReadFormatCapacities");
621 CMassStorageDrive* drive=GetCheckDrive(aLun);
628 TLocalDriveCapsV4 driveInfo;
630 TInt err = drive->Caps(driveInfo);
634 __PRINT1(_L("Can't obtain drive Caps. Err=%d \n"),err);
635 iSenseInfo.SetSense(TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent);
639 TInt64 driveBlocks = (driveInfo.iDriveAtt & KDriveAttLogicallyRemovable) ? driveInfo.iSize : driveInfo.MediaSizeInBytes();
640 driveBlocks /= MAKE_TINT64(0, KDefaultBlockSize);
642 TPtr8 writeBuf(NULL, 0);
643 iTransport->GetCommandBufPtr(writeBuf, KReadFormatCapacitiesCommandLength);
644 writeBuf.FillZ(KReadFormatCapacitiesCommandLength);
646 writeBuf[3] = 0x08; // Capacity List Length
648 TUint32 numBlocks = I64LOW(driveBlocks);
650 writeBuf[4] = static_cast<TUint8>((numBlocks & 0xFF000000) >> 24); // Number of blocks
651 writeBuf[5] = static_cast<TUint8>((numBlocks & 0x00FF0000) >> 16); //
652 writeBuf[6] = static_cast<TUint8>((numBlocks & 0x0000FF00) >> 8); //
653 writeBuf[7] = static_cast<TUint8>((numBlocks & 0x000000FF)); //
655 writeBuf[8] = 0x02; // Formatted size
657 writeBuf[9] = 0x00; // 512 Byte Blocks
658 writeBuf[10] = 0x02; //
659 writeBuf[11] = 0x00; //
661 TPtrC8 writeBuf1 = writeBuf;
663 iTransport->SetupWriteData(writeBuf1);
670 Command Parser for the READ CAPACITY(10) command (0x25)
672 @param aData command data (started form position 1)
673 @param aLun Logic unit number
674 @return ETrue if successful.
676 TBool CScsiProtocol::HandleReadCapacity(TPtrC8& aData, TUint aLun)
678 __FNLOG("CScsiProtocol::HandleReadCapacity");
679 CMassStorageDrive* drive=GetCheckDrive(aLun);
686 TInt pmi = aData[9] & 0x01;
687 TInt lba = aData[3] | aData[4] | aData[5] | aData[6];
689 if (pmi || lba) //do not support partial medium indicator
691 iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
695 TLocalDriveCapsV4 driveInfo;
697 TInt err = drive->Caps(driveInfo);
701 __PRINT1(_L("Can't obtain drive Caps. Err=%d \n"),err);
702 iSenseInfo.SetSense(TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent);
706 TInt64 driveBlocks = 0;
707 if (driveInfo.iDriveAtt & KDriveAttLogicallyRemovable)
709 // Partition Access only
710 driveBlocks = driveInfo.iSize / MAKE_TINT64(0, KDefaultBlockSize);
714 // whole Media Access
715 driveBlocks = driveInfo.MediaSizeInBytes() / MAKE_TINT64(0, KDefaultBlockSize) - 1;
719 TPtr8 writeBuf(NULL, 0);
720 iTransport->GetCommandBufPtr(writeBuf, KReadCapacityCommandLength);
721 writeBuf.FillZ(KReadCapacityCommandLength);
723 if (I64HIGH(driveBlocks) == 0)
725 TUint32 numBlocks = I64LOW(driveBlocks);
727 __PRINT2(_L("Block size=%d, NumBlocks=%d\n"), KDefaultBlockSize, numBlocks);
728 writeBuf[0] = static_cast<TUint8>((numBlocks & 0xFF000000) >> 24); // Number of blocks
729 writeBuf[1] = static_cast<TUint8>((numBlocks & 0x00FF0000) >> 16);
730 writeBuf[2] = static_cast<TUint8>((numBlocks & 0x0000FF00) >> 8);
731 writeBuf[3] = static_cast<TUint8>((numBlocks & 0x000000FF));
735 writeBuf[0] = writeBuf[1] = writeBuf[2] = writeBuf[3] = 0xFF; // indicate that size more then )0xFFFFFFFF
738 writeBuf[4] = static_cast<TUint8>((KDefaultBlockSize & 0xFF000000) >> 24); // Block Size
739 writeBuf[5] = static_cast<TUint8>((KDefaultBlockSize & 0x00FF0000) >> 16);
740 writeBuf[6] = static_cast<TUint8>((KDefaultBlockSize & 0x0000FF00) >> 8);
741 writeBuf[7] = static_cast<TUint8>((KDefaultBlockSize & 0x000000FF));
743 TPtrC8 writeBuf1 = writeBuf;
744 iTransport->SetupWriteData(writeBuf1);
751 Command Parser for the READ10 command (0x28)
753 @param aData command data (started form position 1)
754 @param aLun Logic unit number
755 @return ETrue if successful.
757 TBool CScsiProtocol::HandleRead10(TPtrC8& aData, TUint aLun)
759 __FNLOG("CScsiProtocol::HandleRead10");
760 CMassStorageDrive* drive = GetCheckDrive(aLun);
765 TInt rdProtect = aData[2] >> 5;
768 iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
772 const TUint32 lba = LBA(aData);
773 const TUint16 len = LEN(aData);
775 __PRINT2(_L("READ(10) : LBA = 0x%x, Length = %d (blocks)\n"), lba, len);
779 return ETrue; // do nothing - this is not an error
782 TLocalDriveCapsV4 driveInfo;
783 TInt err = drive->Caps(driveInfo);
786 __PRINT1(_L("Can't obtain drive Caps. Err=%d \n"), err);
787 iSenseInfo.SetSense(TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent);
791 const TInt64 bOffset = MAKE_TINT64(0, lba) * KDefaultBlockSize;
792 const TInt bLength = len * KDefaultBlockSize;
793 const TInt64 theEnd = bOffset + MAKE_TINT64(0, bLength);
794 const TInt64 mediaSize = (driveInfo.iDriveAtt & KDriveAttLogicallyRemovable) ? driveInfo.iSize : driveInfo.MediaSizeInBytes() ;
796 if (theEnd > mediaSize) //check if media big enough for this request
798 __PRINT(_L("err - Request ends out of media\n"));
799 iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::ELbaOutOfRange);
803 #ifdef MSDC_MULTITHREADED
804 iWriteDriveThread->WaitForWriteEmpty();
806 // check if our buffer can hold requested data
807 if (iReadDriveThread->iThreadContext->MaxBufferLength() < bLength)
809 __PRINT(_L("err - Buffer too small\n"));
810 iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
814 // Optimisation note : If the host is reading from sectors it just wrote to,
815 // then we have to force a cache-miss so that the real data is read from the
816 // drive. It would be possible to service the read from the write buffers,
817 // but as the host is probably trying to verify the write data, we don't do
819 if (!iReadDriveThread->ReadDriveData(drive, bOffset, bLength, iWriteDriveThread->IsRecentlyWritten(bOffset,bLength)))
821 iSenseInfo.SetSense(TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent);
825 iWriteDriveThread->SetCommandWrite10(EFalse);
826 TBlockDesc* &desc = iReadDriveThread->iThreadContext->iBuffer.iDescReadPtr;
827 TPtrC8 writeBuf1 = desc->iBuf;
830 TPtr8 writeBuf(NULL, 0);
831 iTransport->GetReadDataBufPtr(writeBuf);
832 // check if our buffer can hold requested data
833 if (writeBuf.MaxLength() < bLength)
835 __PRINT(_L("err - Buffer too small\n"));
836 iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
840 err = drive->Read(bOffset, bLength, writeBuf, drive->IsWholeMediaAccess());
844 __PRINT1(_L("Read failed, err=%d\n"), err);
845 iSenseInfo.SetSense(TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent);
849 TPtrC8 writeBuf1 = writeBuf;
850 #endif // MSDC_MULTITHREADED
851 #ifdef USB_TRANSFER_PUBLISHER
852 iBytesRead[aLun] += writeBuf1.Length();
854 iReadTransferPublisher->StartTimer();
856 // Set up data write to the host
857 iTransport->SetupWriteData(writeBuf1);
864 Command Parser for the WRITE(10) command (0x2A)
866 @param aData command data (started form position 1)
867 @param aLun Logic unit number
868 @return ETrue if successful.
870 TBool CScsiProtocol::HandleWrite10(TPtrC8& aData, TUint aLun)
872 __FNLOG("CScsiProtocol::HandleWrite10");
873 CMassStorageDrive* drive = GetCheckDrive(aLun);
878 TInt wrProtect = aData[2] >> 5;
881 iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
885 const TUint32 lba = LBA(aData);
886 const TUint16 len = LEN(aData);
887 __PRINT2(_L("WRITE(10) : LBA = 0x%x, Length = %d (blocks)\n"), lba, len);
890 return ETrue; // do nothing - this is not an error
893 TLocalDriveCapsV4 driveInfo;
894 TInt err = drive->Caps(driveInfo);
897 __PRINT1(_L("Can't obtain drive Caps. Err=%d \n"), err);
898 iSenseInfo.SetSense(TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent);
901 if (driveInfo.iMediaAtt & KMediaAttWriteProtected ||
902 driveInfo.iMediaAtt & KMediaAttLocked)
904 iSenseInfo.SetSense(TSenseInfo::EDataProtection, TSenseInfo::EWriteProtected);
908 const TInt64 bOffset = MAKE_TINT64(0, lba) * KDefaultBlockSize;
909 iBytesRemain = len * KDefaultBlockSize;
910 const TInt64 theEnd = bOffset + MAKE_TINT64(0, iBytesRemain);
911 const TInt64 mediaSize = (driveInfo.iDriveAtt & KDriveAttLogicallyRemovable) ? driveInfo.iSize : driveInfo.MediaSizeInBytes() ;
913 if (theEnd > mediaSize) //check if media big enough for this request
915 __PRINT(_L("err - Request ends out of media\n"));
916 iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::ELbaOutOfRange);
920 #ifdef MSDC_MULTITHREADED
921 iWriteDriveThread->SetCommandWrite10(ETrue);
924 // Set up the first request for data from the host - either
925 // KMaxBufSize or the entire transfer length, whichever is smallest.
926 TUint thisLength = (iBytesRemain > KMaxBufSize) ? KMaxBufSize : iBytesRemain;
927 thisLength = (thisLength > iMediaWriteSize) ? iMediaWriteSize : thisLength;
930 iLastCommand = EWrite10;
933 iWriteTransferPublisher->StartTimer();
934 iTransport->SetupReadData(thisLength);
941 Command Parser for the VERIFY(10) command (0x2F)
943 @param aData command data (started form position 1)
944 @param aLun Logic unit number
945 @return ETrue if successful.
947 TBool CScsiProtocol::HandleVerify10(TPtrC8& aData, TUint aLun)
949 __FNLOG("CScsiProtocol::HandleVerify10");
950 CMassStorageDrive* drive = GetCheckDrive(aLun);
956 TInt vrProtect = aData[2] >> 5;
959 iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
963 const TUint32 lba = LBA(aData);
964 const TUint16 len = LEN(aData);
965 __PRINT2(_L("VERIFY(10) : LBA = %d, Length = %d (blocks)\n"), lba, len);
967 TInt bytChk = aData[2] & 0x02;
970 return ETrue; // do nothing - this is not an error
973 TLocalDriveCapsV4 driveInfo;
974 TInt err = drive->Caps(driveInfo);
977 __PRINT1(_L("Can't obtain drive Caps. Err=%d \n"), err);
978 iSenseInfo.SetSense(TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent);
982 const TInt64 bOffset = MAKE_TINT64(0, lba) * KDefaultBlockSize;
983 const TInt bLength = len * KDefaultBlockSize;
984 const TInt64 theEnd = bOffset + MAKE_TINT64(0, bLength);
985 const TInt64 mediaSize = (driveInfo.iDriveAtt & KDriveAttLogicallyRemovable) ? driveInfo.iSize : driveInfo.MediaSizeInBytes() ;
987 // check if media big enough for this request
988 if (theEnd > mediaSize)
990 iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::ELbaOutOfRange);
994 // check if our buffer can hold requested data
995 #ifdef MSDC_MULTITHREADED
996 if (iWriteDriveThread->iThreadContext->MaxBufferLength() < bLength)
998 TPtr8 writeBuf(NULL, 0);
999 iTransport->GetReadDataBufPtr(writeBuf);
1000 if (writeBuf.MaxLength() < bLength)
1003 iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
1009 // BYTCHK==0 : Perform a medium verification with no data comparison and not transfer any data from the application client data-out buffer.
1010 // The device should attempt to read from the specified locations
1011 #ifdef MSDC_MULTITHREADED
1012 TPtr8 writeBuf = iWriteDriveThread->iThreadContext->GetReadBuffer(bLength);
1014 writeBuf.SetLength(bLength);
1016 err = drive->Read(bOffset, bLength, writeBuf, drive->IsWholeMediaAccess());
1017 if (err != KErrNone)
1019 iSenseInfo.SetSense(TSenseInfo::EMisCompare);
1025 // BYTCHK==1 : perform a byte-by-byte comparison of user data read from the medium & user data transferred from the application client data-out buffer.
1026 // The host sends data in the data-transport phase, and the device should verify that the received data matches what is stored in the device.
1029 iLastCommand = EVerify10;
1032 iTransport->SetupReadData(bLength);
1039 Called by the transport when the requested data has been read or an error has
1040 occurred during the read.
1042 @param aError Indicate if an error occurs during reading data by transport.
1043 @return KErrAbort if command processing is complete but has failed,
1044 KErrCompletion if sufficient data is available in the buffer to process
1045 the transfer immediately, KErrNotReady if insufficient data is
1046 available in the buffer so the transport should wait for it to arrive,
1047 KErrNone if command processing is complete and was successful.
1049 TInt CScsiProtocol::ReadComplete(TInt aError)
1051 __FNLOG("CScsiProtocol::ReadComplete");
1052 __PRINT1(_L("Error = 0x%X \n"), aError);
1053 const TInt64 bOffset = iOffset;
1054 TUint8 lastCommand = iLastCommand;
1055 TUint lastLun = iLastLun;
1058 iLastCommand = EUndefinedCommand;
1059 iLastLun = KUndefinedLun;
1061 __PRINT1(_L("Last command was: %s\n"),
1062 (lastCommand == EUndefinedCommand) ? _S("Undefined") :
1063 ((lastCommand == EWrite10) ? _S("EWrite10") :
1064 ((lastCommand == EVerify10) ? _S("EVerify10") :
1067 if (aError != KErrNone ||
1068 lastCommand == EUndefinedCommand ||
1069 lastLun == KUndefinedLun)
1071 iSenseInfo.SetSense(TSenseInfo::EAbortedCommand);
1075 CMassStorageDrive* drive = GetCheckDrive(lastLun);
1081 if (lastCommand == EWrite10)
1083 TPtrC8 writeBuf(NULL, 0);
1084 iTransport->GetWriteDataBufPtr(writeBuf);
1086 #ifdef USB_TRANSFER_PUBLISHER
1087 iBytesWritten[lastLun] += writeBuf.Length();
1090 #ifdef MSDC_MULTITHREADED
1091 TInt err = iWriteDriveThread->WriteDriveData(drive, bOffset, writeBuf, ProcessWriteComplete, this);
1093 if (err != KErrNone)
1095 iDeferredSenseInfo.SetSense(TSenseInfo::EMediumError);
1098 TUint thisLength = iWriteDriveThread->WriteBufferLength();
1100 #ifdef MEASURE_AND_DISPLAY_WRITE_TIME
1101 RDebug::Print(_L("SCSI: writing %d bytes\n"), writeBuf.Length());
1105 __PRINT1(_L("SCSI: writing %d bytes\n"), writeBuf.Length());
1109 if (writeBuf[0] == '2')
1112 RDebug::Printf("Injecting error");
1115 RDebug::Printf("%08lx %x [%x] [%x]", bOffset,writeBuf.Length(),
1117 writeBuf[writeBuf.Length()-1]);
1120 TInt err = drive->Write(bOffset, writeBuf, drive->IsWholeMediaAccess());
1123 if (writeBuf[0] == 'x')
1129 #ifdef MEASURE_AND_DISPLAY_WRITE_TIME
1131 const TTimeIntervalMicroSeconds time = t1.MicroSecondsFrom(t0);
1132 const TUint time_ms = I64LOW(time.Int64() / 1000);
1133 RDebug::Print(_L("SCSI: write took %d ms\n"), time_ms);
1135 if (err != KErrNone)
1137 __PRINT1(_L("Error after write = 0x%X \n"), err);
1138 iSenseInfo.SetSense(TSenseInfo::EAbortedCommand);
1142 TUint thisLength = writeBuf.Length();
1143 #endif // MSDC_MULTITHREADED
1144 iOffset = bOffset + MAKE_TINT64(0, thisLength);
1145 iBytesRemain -= thisLength;
1146 if ((TInt)iBytesRemain > 0)
1148 // More data is expected - set up another request to read from the host
1149 iLastCommand = EWrite10;
1152 TUint minLength = (iBytesRemain < iMediaWriteSize) ? iBytesRemain : iMediaWriteSize;
1153 TUint bytesAvail = iTransport->BytesAvailable() & ~(KDefaultBlockSize-1);
1155 TBool wait = EFalse;
1156 thisLength = bytesAvail ? bytesAvail : minLength;
1157 if (thisLength < minLength)
1159 // Not enough data is available at the transport to satisfy the request,
1160 // so return KErrNotReady to indicate that the transport should wait.
1161 thisLength = minLength;
1165 thisLength = (thisLength > KMaxBufSize) ? KMaxBufSize : thisLength;
1167 iTransport->SetupReadData(thisLength);
1169 return wait ? KErrNotReady : KErrCompletion;
1172 else if (lastCommand == EVerify10)
1174 HBufC8* hostData = NULL;
1175 TPtrC8 writeBuf(NULL, 0);
1176 iTransport->GetWriteDataBufPtr(writeBuf);
1177 #ifdef MSDC_MULTITHREADED
1178 TRAPD(err, hostData = HBufC8::NewL(writeBuf.Length()));
1180 TRAPD(err, hostData = HBufC8::NewL(writeBuf.Length()));
1182 if (err != KErrNone || hostData == NULL)
1184 iSenseInfo.SetSense(TSenseInfo::EAbortedCommand, TSenseInfo::EInsufficientRes);
1188 #ifdef MSDC_MULTITHREADED
1190 *hostData = writeBuf;
1191 TPtr8 readBuf = iWriteDriveThread->iThreadContext->GetReadBuffer();
1192 err = drive->Read(bOffset, writeBuf.Length(), readBuf, drive->IsWholeMediaAccess());
1193 if (err == KErrNone)
1195 err = (hostData->Compare(readBuf) == 0) ? KErrNone : KErrCorrupt;
1198 *hostData = writeBuf;
1199 TPtr8 readBuf((TUint8*) writeBuf.Ptr(), writeBuf.Length());
1200 err = drive->Read(bOffset, writeBuf.Length(), readBuf, drive->IsWholeMediaAccess());
1201 if (err == KErrNone)
1203 err = (hostData->Compare(readBuf) == 0) ? KErrNone : KErrCorrupt;
1207 if (err != KErrNone)
1209 iSenseInfo.SetSense(TSenseInfo::EMisCompare);
1214 else // unknown command
1216 iSenseInfo.SetSense(TSenseInfo::EAbortedCommand);
1218 return iSenseInfo.SenseOk() ? KErrNone : KErrAbort;
1223 Command Parser for the MODE SENSE(06) command (0x1A)
1225 @return ETrue if successful.
1227 TBool CScsiProtocol::HandleModeSense(TPtrC8& aData, TUint aLun)
1229 __FNLOG("CScsiProtocol::HandleModeSense");
1231 TInt pageCode = aData[3] & 0x3F;
1232 TUint8 pageControl= static_cast<TUint8>(aData[3] >>6);
1234 // reserve 4 bytes for Length, Media type, Device-specific parameter and Block descriptor length
1236 if (pageCode != KAllPages || pageControl == KChangeableValues)
1238 __PRINT(_L("TSenseInfo::EIllegalRequest,TSenseInfo::EInvalidFieldInCdb"));
1239 iSenseInfo.SetSense(TSenseInfo::EIllegalRequest,TSenseInfo::EInvalidFieldInCdb);
1243 TPtr8 writeBuf(NULL, 0);
1244 iTransport->GetCommandBufPtr(writeBuf, KModeSenseCommandLength);
1245 writeBuf.FillZ(KModeSenseCommandLength);
1247 if (pageControl != KDefaultValues)
1249 //check if drive write protected
1250 CMassStorageDrive* drive=GetCheckDrive(aLun);
1253 __PRINT(_L("drive == null"));
1257 TLocalDriveCapsV4 driveInfo;
1258 TInt err = drive->Caps(driveInfo);
1259 if (err != KErrNone)
1261 __PRINT(_L("TSenseInfo::ENotReady"));
1262 iSenseInfo.SetSense(TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent);
1266 if (driveInfo.iMediaAtt & KMediaAttWriteProtected)
1268 writeBuf[2] = 1<<7; // set SWP bit at the Device Specific parameters
1272 writeBuf[0]=3; //Sending only Mode parameter header
1274 TPtrC8 writeBuf1 = writeBuf;
1276 iTransport->SetupWriteData(writeBuf1);
1278 return (iSenseInfo.SenseOk());