os/kernelhwsrv/userlibandfileserver/fileserver/smassstorage/scsiprot.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
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".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 //
    15 
    16 #include "scsiprot.h"
    17 #ifdef MSDC_MULTITHREADED 
    18 #include "rwdrivethread.h"
    19 #endif // MSDC_MULTITHREADED
    20 #include "massstoragedebug.h"
    21 
    22 // Helper macros
    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])
    25 
    26 
    27 LOCAL_D const TUint KDefaultBlockSize = 0x200;  //default block size for FAT
    28 
    29 LOCAL_D const TUint KUndefinedLun = 0xFFFF;
    30 
    31 LOCAL_D const TUint8 KAllPages = 0x3F;
    32 
    33 LOCAL_D const TUint8 KChangeableValues = 0x1;
    34 LOCAL_D const TUint8 KDefaultValues = 0x2;
    35 
    36 /**
    37 Default constructor for TSenseInfo
    38 */
    39 TSenseInfo::TSenseInfo()
    40 	: iSenseCode(ENoSense),
    41 	  iAdditional(EAscNull),
    42 	  iQualifier(EAscqNull)
    43 	{}
    44 
    45 
    46 /**
    47 Set sense with no additional info.
    48 
    49 @param aSenseCode sense key
    50 */
    51 void TSenseInfo::SetSense(TSenseCode aSenseCode)
    52 	{
    53 	iSenseCode = static_cast<TUint8>(aSenseCode);
    54 	iAdditional = EAscNull;
    55 	iQualifier = EAscqNull;
    56 	}
    57 
    58 
    59 /**
    60 Set sense with additional info.
    61 
    62 @param aSenseCode sense key
    63 @param aAdditional additional sense code (ASC) 
    64 */
    65 void TSenseInfo::SetSense(TSenseCode aSenseCode, TAdditionalCode aAdditional)
    66 
    67 	{
    68 	iSenseCode = static_cast<TUint8>(aSenseCode);
    69 	iAdditional = static_cast<TUint8>(aAdditional);
    70 	iQualifier = EAscqNull;
    71 	}
    72 
    73 
    74 /**
    75 Set sense with additional info and qualifier.
    76 
    77 @param aSenseCode sense key 
    78 @param aAdditional additional sense code (ASC) 
    79 @param aQualifier additional sense code qualifier (ASCQ)
    80 */
    81 void TSenseInfo::SetSense(TSenseCode aSenseCode,
    82 						  TAdditionalCode aAdditional,
    83 						  TAdditionalSenseCodeQualifier aQualifier)
    84 	{
    85 	iSenseCode = static_cast<TUint8>(aSenseCode);
    86 	iAdditional = static_cast<TUint8>(aAdditional);
    87 	iQualifier = static_cast<TUint8>(aQualifier);
    88 	}
    89 
    90 
    91 //-----------------------------------------------
    92 
    93 /**
    94 Creates the CScsiProtocol object.  Called during controller initialisation.
    95 
    96 @param aDriveManager reference to the drive manager object
    97 */
    98 CScsiProtocol* CScsiProtocol::NewL(CDriveManager& aDriveManager)
    99 	{
   100 	CScsiProtocol* self = new (ELeave) CScsiProtocol(aDriveManager);
   101 	CleanupStack::PushL(self);
   102 	self->ConstructL();
   103 	CleanupStack::Pop();
   104 	return self;
   105 	}
   106 
   107 /**
   108 c'tor
   109 
   110 @param aDriveManager reference to the drive manager object
   111 */
   112 CScsiProtocol::CScsiProtocol(CDriveManager& aDriveManager):
   113 	iDriveManager(aDriveManager),
   114 	iLastCommand(EUndefinedCommand),
   115 	iLastLun(KUndefinedLun),
   116 	iMediaWriteSize(KDefaultMediaWriteSize)
   117 	{
   118 	__FNLOG("CScsiProtocol::CScsiProtocol");
   119 
   120 #ifdef USB_TRANSFER_PUBLISHER
   121 	iWriteTransferPublisher = CUsbWriteTransferPublisher::NewL(iBytesWritten);
   122 	iReadTransferPublisher = CUsbReadTransferPublisher::NewL(iBytesRead);
   123 
   124 	for (TUint i = 0; i < KUsbMsMaxDrives; i++)
   125 		{
   126 		iBytesRead[i] = 0;
   127 		iBytesWritten[i] = 0;
   128 		}
   129 #else
   130 	iWriteTransferPublisher = CDriveWriteTransferPublisher::NewL(aDriveManager.iDrives);
   131 	iReadTransferPublisher = CDriveReadTransferPublisher::NewL(aDriveManager.iDrives);
   132 #endif
   133 	}
   134 
   135 
   136 CScsiProtocol::~CScsiProtocol()
   137 	{
   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
   145 
   146 	delete iWriteTransferPublisher;
   147 	delete iReadTransferPublisher;
   148 	}
   149 
   150 
   151 void CScsiProtocol::ConstructL()
   152 	{
   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
   160 	}
   161 
   162 
   163 /**
   164 Associates the transport with the protocol. Called during initialisation of the controller.
   165 
   166 @param aTransport pointer to the transport object
   167 */
   168 void CScsiProtocol::RegisterTransport(MTransportBase* aTransport)
   169 	{
   170 	__FNLOG("CScsiProtocol::RegisterTransport");
   171 	iTransport = aTransport;
   172 	}
   173 
   174 
   175 /**
   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.
   179 
   180 This function is preferably called before actual MS data transfer operation
   181 starts, and usually only once.
   182 
   183 */
   184 void CScsiProtocol::ReportHighSpeedDevice()
   185 	{
   186 	__FNLOG("CScsiProtocol::ReportHighSpeedDevice");
   187 	iMediaWriteSize = KHsMediaWriteSize;
   188 	__PRINT1(_L("HS Device reported: SCSI will use %d bytes disk write size"), iMediaWriteSize);
   189 	}
   190 
   191 
   192 TInt CScsiProtocol::SetScsiParameters(TMassStorageConfig aConfig)
   193 	{
   194 	__FNLOG("CScsiProtocol::SetScsiParameters");
   195 	iConfig = aConfig;
   196 	return KErrNone;
   197 	}
   198 
   199 #ifdef MSDC_MULTITHREADED
   200 
   201 void CScsiProtocol::ProcessWriteComplete (TUint8* aAddress, TAny* aPtr)
   202 	{
   203 	((CScsiProtocol*)aPtr)->iTransport->ProcessReadData(aAddress);
   204 	}
   205 
   206 void CScsiProtocol::InitializeBufferPointers(TPtr8& aDes1, TPtr8& aDes2) // Todo Change name later - InitializeReadBufferSomething
   207 	{
   208 	iReadDriveThread->iThreadContext->iBuffer.SetUpReadBuf(aDes1, aDes2);
   209 	}
   210 #endif
   211 
   212 /**
   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.
   215 
   216 @param aData
   217 
   218 @return  ETrue if command was decoded and executed successfully
   219 */
   220 TBool CScsiProtocol::DecodePacket(TPtrC8& aData, TUint aLun)
   221 	{
   222 	__FNLOG("CScsiProtocol::DecodePacket");
   223 
   224 	TUint8 command = aData[1];
   225 
   226 	if (command != ERequestSense)
   227 		{
   228 		iSenseInfo.SetSense(TSenseInfo::ENoSense);
   229 		}
   230 
   231 	__PRINT2(_L("command = 0x%x lun=%d"), command, aLun);
   232 	switch (command)
   233 		{
   234 		case ETestUnitReady:
   235 			HandleUnitReady(aLun);
   236 			break;
   237 
   238 		case ERequestSense:
   239 			HandleRequestSense(aData);
   240 			break;
   241 
   242 		case EInquiry:
   243 			HandleInquiry(aData, aLun);
   244 			break;
   245 
   246 		case EModeSense:
   247 			HandleModeSense(aData, aLun);
   248 			break;
   249 
   250 		case EStartStopUnit:
   251 			HandleStartStopUnit(aData, aLun);
   252 			break;
   253 
   254 		case EPreventMediaRemoval:
   255 			HandlePreventMediaRemoval(aData, aLun);
   256 			break;
   257 
   258 		case EReadCapacity:
   259 			HandleReadCapacity(aData, aLun);
   260 			break;
   261 
   262 		case ERead10:
   263 			HandleRead10(aData, aLun);
   264 			break;
   265 
   266 		case EWrite10:
   267 			HandleWrite10(aData,aLun);
   268 			break;
   269 
   270 		case EVerify10:
   271 			HandleVerify10(aData, aLun);
   272 			break;
   273 
   274 		case EReadFormatCapacities:
   275 			HandleReadFormatCapacities(aLun);
   276 			break;
   277 
   278 		default:
   279 			iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidCmdCode);
   280 		}
   281 	__PRINT1(_L("DecodePacket result = %d"), iSenseInfo.SenseOk());
   282 	return(iSenseInfo.SenseOk());
   283 	}
   284 
   285 
   286 /**
   287 Checks if drive ready
   288 
   289 @param aLun Logic unit number 
   290 @return pointer to drive correspondent to LUN if drive mounted and ready, NULL otherwise
   291 */
   292 CMassStorageDrive* CScsiProtocol::GetCheckDrive(TUint aLun)
   293 	{
   294 	__FNLOG("CScsiProtocol::GetCheckDrive");
   295 	TInt err=KErrNone;
   296 
   297 #ifdef MSDC_MULTITHREADED
   298 	// check for deferred errors
   299 	if (iWriteDriveThread->DeferredError())
   300 		{
   301 		iWriteDriveThread->ClearDeferredError();
   302 		iDeferredSenseInfo.SetSense(TSenseInfo::EMediumError);
   303 		return NULL;
   304 		}
   305 
   306 #endif
   307 
   308 	CMassStorageDrive* drive= iDriveManager.Drive(aLun, err);
   309 
   310 	if (err !=KErrNone || drive == NULL)
   311 		{
   312 		__PRINT(_L("No drive available\n"));
   313 		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::ELuNotSupported);
   314 		return NULL;
   315 		}
   316 
   317 	CMassStorageDrive::TMountState mountState = drive->MountState();
   318 
   319 	if (mountState == CMassStorageDrive::EDisconnected || mountState == CMassStorageDrive::EConnecting)
   320 		{
   321 		__PRINT(_L("Drive disconnected\n"));
   322 		iSenseInfo.SetSense(TSenseInfo::ENotReady,
   323 							TSenseInfo::EMediaNotPresent);
   324 		return NULL;
   325 		}
   326 
   327 	CMassStorageDrive::TDriveState state = drive->CheckDriveState();
   328 	if (state == CMassStorageDrive::EMediaNotPresent || state == CMassStorageDrive::ELocked)
   329 		{
   330 		__PRINT1(_L("Media not present or locked. (state =0x%X)\n"),state);
   331 		iSenseInfo.SetSense(TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent);
   332 		return NULL;
   333 		}
   334 
   335 	if (drive->IsMediaChanged(ETrue))  //reset "media changed" status
   336 		{
   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
   341 		return NULL;
   342 		}
   343 
   344 	if (mountState == CMassStorageDrive::EDisconnecting)
   345 		{
   346 		__PRINT(_L("Drive disconnecting\n"));
   347 		iSenseInfo.SetSense(TSenseInfo::ENotReady,
   348 							TSenseInfo::EMediaNotPresent);
   349 		return NULL;
   350 		}
   351 
   352 	return drive;
   353 	}
   354 
   355 
   356 /**
   357 Command Parser for the UNIT READY command (0x00)
   358 
   359 @param aLun Logic unit number 
   360 @return ETrue if successful, 
   361 */
   362 TBool CScsiProtocol::HandleUnitReady(TUint aLun)
   363 	{
   364 	__FNLOG("CScsiProtocol::HandleUnitReady");
   365 #ifdef MSDC_MULTITHREADED
   366 	iWriteDriveThread->WaitForWriteEmpty();
   367 #endif
   368 	return GetCheckDrive(aLun) ? (TBool)ETrue : (TBool)EFalse;
   369 	}
   370 
   371 
   372 /**
   373 Command Parser for the REQUEST SENSE command (0x03)
   374 
   375 @return ETrue if successful, 
   376 */
   377 TBool CScsiProtocol::HandleRequestSense(TPtrC8& aData)
   378 	{
   379 	__FNLOG("CScsiProtocol::HandleRequestSense");
   380 	TUint length = aData[5];
   381 	__PRINT1(_L("length = %d\n"), length);
   382 	
   383 	TPtr8 writeBuf(NULL, 0);
   384 	iTransport->GetCommandBufPtr(writeBuf, KRequestSenseCommandLength);
   385 	writeBuf.FillZ(KRequestSenseCommandLength);
   386 
   387 	TSenseInfo* senseInfo;
   388 #ifdef MSDC_MULTITHREADED
   389 	if (!iDeferredSenseInfo.SenseOk())
   390 		{
   391 		writeBuf[00] = 0x71; //(deferred errors)
   392 		senseInfo = &iDeferredSenseInfo;
   393 		}
   394 	else
   395 		{
   396 		writeBuf[00] = 0x70; //(current errors)
   397 		senseInfo = &iSenseInfo;
   398 		}
   399 #else
   400 	senseInfo = &iSenseInfo;
   401 	writeBuf[00] = 0x70; //(current errors)
   402 #endif
   403 
   404 	writeBuf[02] = static_cast<TUint8>(senseInfo->iSenseCode & 0x0F);
   405 
   406 	writeBuf[12] = senseInfo->iAdditional;
   407 	writeBuf[13] = senseInfo->iQualifier;
   408 	if (length<18 && length >=8) 
   409 		{
   410 		writeBuf.SetLength(length);  //length of response code data
   411 		writeBuf[07] = TUint8(length - 8);  //additional sence length
   412 		}
   413 	else if (length >= KRequestSenseCommandLength)
   414 		{
   415 		writeBuf[07] = KRequestSenseCommandLength - 8;	// we have max 18 byte to send
   416 		}
   417 
   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]);
   420  
   421 	TPtrC8 writeBuf1 = writeBuf.Left(length);
   422 
   423 	iTransport->SetupWriteData(writeBuf1);
   424 
   425 	// clear the sense info
   426 	iSenseInfo.SetSense(TSenseInfo::ENoSense);
   427 
   428 #ifdef MSDC_MULTITHREADED
   429 	iDeferredSenseInfo.SetSense(TSenseInfo::ENoSense);
   430 #endif
   431 
   432 	return ETrue;
   433 	}
   434 
   435 
   436 /**
   437 Command Parser for the INQUIRY command (0x12)
   438 
   439 @param aLun Logic unit number 
   440 @return ETrue if successful, 
   441 */
   442 TBool CScsiProtocol::HandleInquiry(TPtrC8& aData, TUint  aLun )
   443 	{
   444 	__FNLOG("CScsiProtocol::HandleInquiry");
   445 
   446 	TBool cmdDt = aData[2] & 0x2;
   447 	TBool evpd  = aData[2] & 0x1;
   448 	TUint8 page = aData[3];
   449 	if (cmdDt || evpd || page || aLun >= KUsbMsMaxDrives)
   450 		{
   451 		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb); 
   452 		return EFalse;
   453 		}
   454 
   455 	TPtr8 writeBuf(NULL, 0);
   456 	iTransport->GetCommandBufPtr(writeBuf, KInquiryCommandLength);
   457 	writeBuf.FillZ(KInquiryCommandLength);
   458 
   459 	writeBuf[1] = 0x80;	// MSB: RMB : Removable
   460 	writeBuf[3] = 0x02;	// AERC, TrmTsk, NormACA, Response Data Format
   461 	writeBuf[4] = 0x1F;	// Additional Length
   462 
   463 	TPtr8 vendorId(&writeBuf[8], 8, 8);		// Vendor ID (Vendor Specific/Logged by T10)
   464 	vendorId.Fill(' ', 8);
   465 	vendorId.Copy(iConfig.iVendorId);
   466 
   467 	TPtr8 productId(&writeBuf[16], 16, 16);	// Product ID (Vendor Specific)
   468 	productId.Fill(' ', 16);
   469 	productId.Copy(iConfig.iProductId);
   470 
   471 	TPtr8 productRev(&writeBuf[32], 4, 4);		// Product Revision Level (Vendor Specific)
   472 	productRev.Fill(' ', 4);
   473 	productRev.Copy(iConfig.iProductRev);
   474 
   475     TUint length = aData[5];
   476 
   477 	TPtrC8 writeBuf1 = writeBuf.Left(length);
   478 	iTransport->SetupWriteData(writeBuf1);
   479 
   480 	iSenseInfo.SetSense(TSenseInfo::ENoSense); 
   481 	return ETrue;
   482 	}
   483 
   484 
   485 /**
   486  Command Parser for the START STOP UNIT command (0x1B)
   487  
   488  @param aData command data (started form position 1)
   489  @param aLun Logic unit number 
   490  @return ETrue if successful, TFalse otherwise
   491  */
   492 TBool CScsiProtocol::HandleStartStopUnit(TPtrC8& aData, TUint aLun)
   493 	{
   494 	__FNLOG("CScsiProtocol::HandleStartStopUnit");
   495 
   496 	const TUint8 KStartMask = 0x01;
   497 	const TUint8 KImmedMask = 0x01;
   498 	const TUint8 KLoejMask = 0x02;
   499 
   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;
   503 
   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);
   507 
   508 	__PRINT1(_L("LOEJ = %d\n"), loej);
   509 
   510 	TInt err(KErrNone);
   511 	if (loej)
   512 		{
   513 		if(start)	//Start unit
   514 			{
   515 			err = iDriveManager.Connect(aLun);
   516 			__PRINT(_L("Load media\n"));
   517 
   518 #ifdef USB_TRANSFER_PUBLISHER
   519 			iBytesRead[aLun] = 0;
   520 			iBytesWritten[aLun] = 0;
   521 #endif
   522 			// publish the initial values
   523 			iWriteTransferPublisher->DoPublishDataTransferredEvent();
   524 			iReadTransferPublisher->DoPublishDataTransferredEvent();
   525 			}
   526 		else		//Stop unit 
   527 			{
   528 			iDriveManager.SetCritical(aLun, EFalse);
   529 			err = iDriveManager.Disconnect(aLun);
   530 			__PRINT(_L("Unload media\n"));
   531 			}
   532 		}
   533 
   534 	if (err !=KErrNone)  //actually we have error here only if the LUN is incorrect 
   535 		{
   536 		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::ELuNotSupported);
   537 		return EFalse;
   538 		}
   539 	if (immed)
   540 		{
   541 		return ETrue;
   542 		}
   543 
   544 	CMassStorageDrive* drive= iDriveManager.Drive(aLun, err);
   545 
   546 	if (err !=KErrNone || drive == NULL)
   547 		{
   548 		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::ELuNotSupported);
   549 		return EFalse;
   550 		}
   551 
   552 	TInt  timeLeft (20);   // 1 sec timeout
   553 	CMassStorageDrive::TMountState mountState;
   554 
   555 	do 
   556 		{
   557 		User::After(1000 * 50);		// 50 mSec
   558 		--timeLeft;
   559 		mountState = drive->MountState();
   560 
   561 		if ((!start && mountState != CMassStorageDrive::EConnected)
   562 			 ||
   563 			 (start &&
   564 				(mountState == CMassStorageDrive::EDisconnecting || 
   565 				mountState == CMassStorageDrive::EConnected))
   566 			)
   567 			{
   568 			return ETrue;
   569 			}
   570 		} while (timeLeft>0);
   571 
   572 	//timeout happend
   573 	iSenseInfo.SetSense(TSenseInfo::ENotReady,
   574 						TSenseInfo::EAscLogicalUnitDoesNotRespondToSelection);
   575 	return EFalse;
   576 	}
   577 
   578 
   579 /**
   580 Command Parser for the PREVENT/ALLOW MEDIA REMOVAL command (0x1E)
   581 
   582 @param aData command data (started form position 1)
   583 @param aLun Logic unit number 
   584 @return ETrue if successful.
   585 */
   586 TBool CScsiProtocol::HandlePreventMediaRemoval(TPtrC8& aData, TUint aLun)
   587 	{
   588 	__FNLOG("CScsiProtocol::HandlePreventMediaRemoval");
   589 	CMassStorageDrive* drive=GetCheckDrive(aLun);
   590 
   591 	if (drive == NULL)
   592 		{
   593 		return EFalse;
   594 		}
   595 
   596 	TInt prevent = aData[5] & 0x01;
   597 	__PRINT1(_L("prevent = %d\n"), prevent);
   598 	iDriveManager.SetCritical(aLun, prevent);
   599 
   600 	return ETrue;
   601 	}
   602 
   603 
   604 /** Cancel active state, Invoked by transnport when it stops */
   605 TInt CScsiProtocol::Cancel()
   606 	{
   607 	iDriveManager.SetCritical(CDriveManager::KAllLuns, EFalse);
   608 	return KErrNone;
   609 	}
   610 
   611 
   612 TBool CScsiProtocol::HandleReadFormatCapacities(TUint aLun)
   613 /**
   614  * Command Parser for the READ FORMAT CAPACITIES command (0x23)
   615  *
   616  * @return ETrue if successful, else a standard Symbian OS error code.
   617  */
   618 	{
   619 	__FNLOG("CScsiProtocol::HandleReadFormatCapacities");
   620 
   621 	CMassStorageDrive* drive=GetCheckDrive(aLun);
   622 
   623 	if (drive == NULL)
   624 		{
   625 		return EFalse;
   626 		}
   627 
   628 	TLocalDriveCapsV4 driveInfo;
   629 
   630 	TInt err = drive->Caps(driveInfo);
   631 
   632 	if(err != KErrNone)
   633 		{
   634 		__PRINT1(_L("Can't obtain drive Caps. Err=%d \n"),err);
   635 		iSenseInfo.SetSense(TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent);
   636 		return EFalse;
   637 		}
   638 
   639 	TInt64 driveBlocks = (driveInfo.iDriveAtt & KDriveAttLogicallyRemovable) ? driveInfo.iSize : driveInfo.MediaSizeInBytes();
   640 	driveBlocks /= MAKE_TINT64(0, KDefaultBlockSize);
   641 
   642 	TPtr8 writeBuf(NULL, 0);
   643 	iTransport->GetCommandBufPtr(writeBuf, KReadFormatCapacitiesCommandLength);
   644 	writeBuf.FillZ(KReadFormatCapacitiesCommandLength);
   645 
   646 	writeBuf[3] = 0x08;	// Capacity List Length
   647 
   648 	TUint32 numBlocks = I64LOW(driveBlocks);
   649 
   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));		//
   654 
   655 	writeBuf[8] = 0x02;	// Formatted size
   656 
   657 	writeBuf[9]  = 0x00;	// 512 Byte Blocks
   658 	writeBuf[10] = 0x02;	// 
   659 	writeBuf[11] = 0x00;	// 
   660 
   661 	TPtrC8 writeBuf1 = writeBuf;
   662 
   663 	iTransport->SetupWriteData(writeBuf1);
   664 
   665 	return ETrue;
   666 	}
   667 
   668 
   669 /**
   670 Command Parser for the READ CAPACITY(10) command (0x25)
   671 
   672 @param aData command data (started form position 1)
   673 @param aLun Logic unit number 
   674 @return ETrue if successful.
   675 */
   676 TBool CScsiProtocol::HandleReadCapacity(TPtrC8& aData, TUint aLun)
   677 	{
   678 	__FNLOG("CScsiProtocol::HandleReadCapacity");
   679 	CMassStorageDrive* drive=GetCheckDrive(aLun);
   680 
   681 	if (drive == NULL)
   682 		{
   683 		return EFalse;
   684 		}
   685 
   686 	TInt pmi = aData[9] & 0x01;
   687 	TInt lba = aData[3] | aData[4] | aData[5] | aData[6];
   688 
   689 	if (pmi || lba)   //do not support partial medium indicator
   690 		{
   691 		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
   692 		return EFalse;
   693 		} 
   694 
   695 	TLocalDriveCapsV4 driveInfo;
   696 
   697 	TInt err = drive->Caps(driveInfo);
   698 
   699 	if(err != KErrNone)
   700 		{
   701 		__PRINT1(_L("Can't obtain drive Caps. Err=%d \n"),err);
   702 		iSenseInfo.SetSense(TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent);
   703 		return EFalse;
   704 		}
   705 
   706 	TInt64 driveBlocks = 0;
   707 	if (driveInfo.iDriveAtt & KDriveAttLogicallyRemovable)
   708 		{
   709 		// Partition Access only 
   710 		driveBlocks = driveInfo.iSize / MAKE_TINT64(0, KDefaultBlockSize);
   711 		}
   712 	else
   713 		{
   714 		// whole Media Access
   715 		driveBlocks = driveInfo.MediaSizeInBytes() / MAKE_TINT64(0, KDefaultBlockSize) - 1;
   716 		}
   717 	
   718 
   719 	TPtr8 writeBuf(NULL, 0);
   720 	iTransport->GetCommandBufPtr(writeBuf, KReadCapacityCommandLength);
   721 	writeBuf.FillZ(KReadCapacityCommandLength);
   722 
   723 	if (I64HIGH(driveBlocks) == 0)
   724 		{
   725 		TUint32 numBlocks = I64LOW(driveBlocks);
   726 
   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));
   732 		}
   733 	else   
   734 		{
   735 		writeBuf[0] = writeBuf[1] = writeBuf[2] = writeBuf[3] = 0xFF;  // indicate that size more then )0xFFFFFFFF
   736 		}
   737 
   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));
   742 
   743 	TPtrC8 writeBuf1 = writeBuf;
   744 	iTransport->SetupWriteData(writeBuf1);
   745 
   746 	return KErrNone;
   747 	}
   748 
   749 
   750 /**
   751 Command Parser for the READ10 command (0x28)
   752 
   753 @param aData command data (started form position 1)
   754 @param aLun Logic unit number
   755 @return ETrue if successful.
   756 */
   757 TBool CScsiProtocol::HandleRead10(TPtrC8& aData, TUint aLun)
   758 	{
   759 	__FNLOG("CScsiProtocol::HandleRead10");
   760 	CMassStorageDrive* drive = GetCheckDrive(aLun);
   761 	if (drive == NULL)
   762 		{
   763 		return EFalse;
   764 		}
   765 	TInt rdProtect = aData[2] >> 5;
   766 	if (rdProtect)
   767 		{
   768 		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
   769 		return EFalse;
   770 		}
   771 
   772 	const TUint32 lba = LBA(aData);
   773 	const TUint16 len = LEN(aData);
   774 
   775 	__PRINT2(_L("READ(10) : LBA = 0x%x, Length = %d  (blocks)\n"), lba, len);
   776 
   777 	if (!len)
   778 		{
   779 		return ETrue; // do nothing - this is not an error
   780 		}
   781 
   782 	TLocalDriveCapsV4 driveInfo;
   783 	TInt err = drive->Caps(driveInfo);
   784 	if (err != KErrNone)
   785 		{
   786 		__PRINT1(_L("Can't obtain drive Caps. Err=%d \n"), err);
   787 		iSenseInfo.SetSense(TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent);
   788 		return EFalse;
   789 		}
   790 
   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() ;
   795 	
   796 	if (theEnd > mediaSize)  //check if media big enough for this request
   797 		{
   798 		__PRINT(_L("err - Request ends out of media\n"));
   799 		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::ELbaOutOfRange);
   800 		return EFalse;
   801 		}
   802 
   803 #ifdef MSDC_MULTITHREADED
   804 	iWriteDriveThread->WaitForWriteEmpty();
   805 
   806 	// check if our buffer can hold requested data
   807 	if (iReadDriveThread->iThreadContext->MaxBufferLength() < bLength)
   808 		{
   809 		__PRINT(_L("err - Buffer too small\n"));
   810 		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
   811 		return EFalse;
   812 		}
   813 
   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 
   818     // that for now. 
   819 	if (!iReadDriveThread->ReadDriveData(drive, bOffset, bLength, iWriteDriveThread->IsRecentlyWritten(bOffset,bLength)))
   820 		{
   821 		iSenseInfo.SetSense(TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent);
   822 		return EFalse;
   823 		}
   824 
   825 	iWriteDriveThread->SetCommandWrite10(EFalse);
   826 	TBlockDesc* &desc = iReadDriveThread->iThreadContext->iBuffer.iDescReadPtr;
   827 	TPtrC8 writeBuf1 = desc->iBuf;
   828 #else
   829 	
   830 	TPtr8 writeBuf(NULL, 0);
   831 	iTransport->GetReadDataBufPtr(writeBuf);
   832 	// check if our buffer can hold requested data
   833 	if (writeBuf.MaxLength() < bLength)
   834 		{
   835 		__PRINT(_L("err - Buffer too small\n"));
   836 		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
   837 		return EFalse;
   838 		}
   839 
   840 	err = drive->Read(bOffset, bLength, writeBuf, drive->IsWholeMediaAccess());
   841 
   842 	if (err != KErrNone)
   843 		{
   844 		__PRINT1(_L("Read failed, err=%d\n"), err);
   845 		iSenseInfo.SetSense(TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent);
   846 		return EFalse;
   847 		}
   848 
   849 	TPtrC8 writeBuf1 = writeBuf;
   850 #endif // MSDC_MULTITHREADED
   851 #ifdef USB_TRANSFER_PUBLISHER
   852 	iBytesRead[aLun] += writeBuf1.Length();
   853 #endif
   854 	iReadTransferPublisher->StartTimer();
   855 
   856 	// Set up data write to the host
   857 	iTransport->SetupWriteData(writeBuf1);
   858 
   859 	return ETrue;
   860 	}
   861 
   862 
   863 /**
   864 Command Parser for the WRITE(10) command (0x2A)
   865 
   866 @param aData command data (started form position 1)
   867 @param aLun Logic unit number
   868 @return ETrue if successful.
   869 */
   870 TBool CScsiProtocol::HandleWrite10(TPtrC8& aData, TUint aLun)
   871 	{
   872 	__FNLOG("CScsiProtocol::HandleWrite10");
   873 	CMassStorageDrive* drive = GetCheckDrive(aLun);
   874 	if (drive == NULL)
   875 		{
   876 		return EFalse;
   877 		}
   878 	TInt wrProtect = aData[2] >> 5;
   879 	if (wrProtect)
   880 		{
   881 		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
   882 		return EFalse;
   883 		}
   884 
   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);
   888 	if (!len)
   889 		{
   890 		return ETrue; // do nothing - this is not an error
   891 		}
   892 
   893 	TLocalDriveCapsV4 driveInfo;
   894 	TInt err = drive->Caps(driveInfo);
   895 	if (err != KErrNone)
   896 		{
   897 		__PRINT1(_L("Can't obtain drive Caps. Err=%d \n"), err);
   898 		iSenseInfo.SetSense(TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent);
   899 		return EFalse;
   900 		}
   901 	if (driveInfo.iMediaAtt & KMediaAttWriteProtected ||
   902 		driveInfo.iMediaAtt & KMediaAttLocked)
   903 		{
   904 		iSenseInfo.SetSense(TSenseInfo::EDataProtection, TSenseInfo::EWriteProtected);
   905 		return EFalse;
   906 		}
   907 
   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() ;
   912 
   913 	if (theEnd > mediaSize)  //check if media big enough for this request
   914 		{
   915 		__PRINT(_L("err - Request ends out of media\n"));
   916 		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::ELbaOutOfRange);
   917 		return EFalse;
   918 		}
   919 
   920 #ifdef MSDC_MULTITHREADED
   921 	iWriteDriveThread->SetCommandWrite10(ETrue);
   922 #endif
   923 
   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;
   928 
   929 	iOffset = bOffset;
   930 	iLastCommand = EWrite10;
   931 	iLastLun = aLun;
   932 
   933 	iWriteTransferPublisher->StartTimer();
   934 	iTransport->SetupReadData(thisLength);
   935 
   936 	return ETrue;
   937 	}
   938 
   939 
   940 /**
   941 Command Parser for the VERIFY(10) command (0x2F)
   942 
   943 @param aData command data (started form position 1)
   944 @param aLun Logic unit number
   945 @return ETrue if successful.
   946 */
   947 TBool CScsiProtocol::HandleVerify10(TPtrC8& aData, TUint aLun)
   948 	{
   949 	__FNLOG("CScsiProtocol::HandleVerify10");
   950 	CMassStorageDrive* drive = GetCheckDrive(aLun);
   951 	if (drive == NULL)
   952 		{
   953 		return EFalse;
   954 		}
   955 
   956 	TInt vrProtect = aData[2] >> 5;
   957 	if (vrProtect)
   958 		{
   959 		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
   960 		return EFalse;
   961 		}
   962 
   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);
   966 
   967 	TInt bytChk = aData[2] & 0x02;
   968 	if (!len)
   969 		{
   970 		return ETrue; // do nothing - this is not an error
   971 		}
   972 
   973 	TLocalDriveCapsV4 driveInfo;
   974 	TInt err = drive->Caps(driveInfo);
   975 	if (err != KErrNone)
   976 		{
   977 		__PRINT1(_L("Can't obtain drive Caps. Err=%d \n"), err);
   978 		iSenseInfo.SetSense(TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent);
   979 		return EFalse;
   980 		}
   981 
   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() ;
   986 
   987 	// check if media big enough for this request
   988 	if (theEnd > mediaSize)
   989 		{
   990 		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::ELbaOutOfRange);
   991 		return EFalse;
   992 		}
   993 
   994 	// check if our buffer can hold requested data
   995 #ifdef MSDC_MULTITHREADED
   996 	if (iWriteDriveThread->iThreadContext->MaxBufferLength() < bLength)
   997 #else
   998 	TPtr8 writeBuf(NULL, 0);
   999 	iTransport->GetReadDataBufPtr(writeBuf);
  1000 	if (writeBuf.MaxLength() < bLength)
  1001 #endif
  1002 		{
  1003 		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
  1004 		return EFalse;
  1005 		}
  1006 
  1007 	if (!bytChk)
  1008 		{
  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);
  1013 #else
  1014 		writeBuf.SetLength(bLength);
  1015 #endif
  1016 		err = drive->Read(bOffset, bLength, writeBuf, drive->IsWholeMediaAccess());
  1017 		if (err != KErrNone)
  1018 			{
  1019 			iSenseInfo.SetSense(TSenseInfo::EMisCompare);
  1020 			return EFalse;
  1021 			}
  1022 		return ETrue;
  1023 		}
  1024 
  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.
  1027 
  1028 	iOffset = bOffset;
  1029 	iLastCommand = EVerify10;
  1030 	iLastLun = aLun;
  1031 
  1032 	iTransport->SetupReadData(bLength);
  1033 
  1034 	return ETrue;
  1035 	}
  1036 
  1037 
  1038 /**
  1039 Called by the transport when the requested data has been read or an error has
  1040 occurred during the read.
  1041 
  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.
  1048 */
  1049 TInt CScsiProtocol::ReadComplete(TInt aError)
  1050 	{
  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;
  1056 
  1057 	iOffset = 0;
  1058 	iLastCommand = EUndefinedCommand;
  1059 	iLastLun = KUndefinedLun;
  1060 
  1061 	__PRINT1(_L("Last command was: %s\n"),
  1062 			 (lastCommand == EUndefinedCommand) ? _S("Undefined") :
  1063 			 ((lastCommand == EWrite10) ? _S("EWrite10") :
  1064 			  ((lastCommand == EVerify10) ? _S("EVerify10") :
  1065 			   _S("Unknown"))));
  1066 
  1067 	if (aError != KErrNone ||
  1068 		lastCommand == EUndefinedCommand ||
  1069 		lastLun == KUndefinedLun)
  1070 		{
  1071 		iSenseInfo.SetSense(TSenseInfo::EAbortedCommand);
  1072 		return KErrAbort;
  1073 		}
  1074 
  1075 	CMassStorageDrive* drive = GetCheckDrive(lastLun);
  1076 	if (drive == NULL)
  1077 		{
  1078 		return KErrAbort;
  1079 		}
  1080 
  1081 	if (lastCommand == EWrite10)
  1082 		{
  1083 		TPtrC8 writeBuf(NULL, 0);
  1084 		iTransport->GetWriteDataBufPtr(writeBuf);
  1085 		
  1086 #ifdef USB_TRANSFER_PUBLISHER
  1087 	iBytesWritten[lastLun] += writeBuf.Length();
  1088 #endif
  1089 
  1090 #ifdef MSDC_MULTITHREADED
  1091 		TInt err = iWriteDriveThread->WriteDriveData(drive, bOffset, writeBuf, ProcessWriteComplete, this);
  1092 
  1093 		if (err != KErrNone)
  1094 			{
  1095 			iDeferredSenseInfo.SetSense(TSenseInfo::EMediumError);
  1096 			}
  1097 
  1098 		TUint thisLength = iWriteDriveThread->WriteBufferLength();
  1099 #else
  1100 #ifdef MEASURE_AND_DISPLAY_WRITE_TIME
  1101 		RDebug::Print(_L("SCSI: writing %d bytes\n"), writeBuf.Length());
  1102 		TTime t0, t1;
  1103 		t0.HomeTime();
  1104 #else
  1105 		__PRINT1(_L("SCSI: writing %d bytes\n"), writeBuf.Length());
  1106 #endif
  1107 
  1108 #ifdef INJECT_ERROR
  1109 		if (writeBuf[0] == '2')
  1110 		{
  1111 			writeBuf[0] = 'x';
  1112 			RDebug::Printf("Injecting error");
  1113 		}
  1114 
  1115 		RDebug::Printf("%08lx %x [%x] [%x]", bOffset,writeBuf.Length(), 
  1116 			writeBuf[0],
  1117 			writeBuf[writeBuf.Length()-1]);
  1118 #endif
  1119 		
  1120 		TInt err = drive->Write(bOffset, writeBuf, drive->IsWholeMediaAccess());
  1121 
  1122 #ifdef INJECT_ERROR
  1123 		if (writeBuf[0] == 'x')
  1124 		{
  1125 			err = KErrUnknown;
  1126 		}
  1127 #endif
  1128 
  1129 #ifdef MEASURE_AND_DISPLAY_WRITE_TIME
  1130 		t1.HomeTime();
  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);
  1134 #endif
  1135 		if (err != KErrNone)
  1136 			{
  1137 			__PRINT1(_L("Error after write = 0x%X \n"), err);
  1138 			iSenseInfo.SetSense(TSenseInfo::EAbortedCommand);
  1139 			return KErrAbort;
  1140 			}
  1141 
  1142 		TUint thisLength = writeBuf.Length();
  1143 #endif // MSDC_MULTITHREADED
  1144 		iOffset = bOffset + MAKE_TINT64(0, thisLength);
  1145 		iBytesRemain -= thisLength;
  1146 		if ((TInt)iBytesRemain > 0)
  1147 			{
  1148 			// More data is expected - set up another request to read from the host
  1149 			iLastCommand = EWrite10;
  1150 			iLastLun = lastLun;
  1151 
  1152 			TUint minLength = (iBytesRemain < iMediaWriteSize) ? iBytesRemain : iMediaWriteSize;
  1153 			TUint bytesAvail = iTransport->BytesAvailable() & ~(KDefaultBlockSize-1);
  1154 
  1155 			TBool wait = EFalse;
  1156 			thisLength = bytesAvail ? bytesAvail : minLength;
  1157 			if (thisLength < minLength)
  1158 				{
  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;
  1162 				wait = ETrue;
  1163 				}
  1164 
  1165 			thisLength = (thisLength > KMaxBufSize) ? KMaxBufSize : thisLength;
  1166 
  1167 			iTransport->SetupReadData(thisLength);
  1168 
  1169 			return wait ? KErrNotReady : KErrCompletion;
  1170 			}
  1171 		}
  1172 	else if (lastCommand == EVerify10)
  1173 		{
  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()));
  1179 #else
  1180 		TRAPD(err, hostData = HBufC8::NewL(writeBuf.Length()));
  1181 #endif
  1182 		if (err != KErrNone || hostData == NULL)
  1183 			{
  1184 			iSenseInfo.SetSense(TSenseInfo::EAbortedCommand, TSenseInfo::EInsufficientRes);
  1185 			return KErrAbort;
  1186 			}
  1187 
  1188 #ifdef MSDC_MULTITHREADED
  1189 		// copy the data
  1190 		*hostData = writeBuf;
  1191 		TPtr8 readBuf = iWriteDriveThread->iThreadContext->GetReadBuffer(); 
  1192 		err = drive->Read(bOffset, writeBuf.Length(), readBuf, drive->IsWholeMediaAccess());
  1193 		if (err == KErrNone)
  1194 			{
  1195 			err = (hostData->Compare(readBuf) == 0) ? KErrNone : KErrCorrupt;
  1196 			}
  1197 #else
  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)
  1202 			{
  1203 			err = (hostData->Compare(readBuf) == 0) ? KErrNone : KErrCorrupt;
  1204 			}
  1205 #endif
  1206 
  1207 		if (err != KErrNone)
  1208 			{
  1209 			iSenseInfo.SetSense(TSenseInfo::EMisCompare);
  1210 			}
  1211 
  1212 		delete hostData;
  1213 		}
  1214 	else // unknown command
  1215 		{
  1216 		iSenseInfo.SetSense(TSenseInfo::EAbortedCommand);
  1217 		}
  1218 	return iSenseInfo.SenseOk() ? KErrNone : KErrAbort;
  1219 	}
  1220 
  1221 
  1222 /**
  1223 Command Parser for the MODE SENSE(06) command (0x1A)
  1224 
  1225 @return ETrue if successful.
  1226 */
  1227 TBool CScsiProtocol::HandleModeSense(TPtrC8& aData, TUint aLun)
  1228 	{
  1229 	__FNLOG("CScsiProtocol::HandleModeSense");
  1230 
  1231 	TInt pageCode = aData[3] & 0x3F;
  1232 	TUint8 pageControl= static_cast<TUint8>(aData[3] >>6);
  1233 
  1234 	// reserve 4 bytes for Length, Media type, Device-specific parameter and Block descriptor length
  1235 
  1236 	if (pageCode != KAllPages || pageControl == KChangeableValues) 
  1237 		{
  1238 		__PRINT(_L("TSenseInfo::EIllegalRequest,TSenseInfo::EInvalidFieldInCdb"));
  1239 		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest,TSenseInfo::EInvalidFieldInCdb);
  1240 		return EFalse;
  1241 		}
  1242 
  1243 	TPtr8 writeBuf(NULL, 0);
  1244 	iTransport->GetCommandBufPtr(writeBuf, KModeSenseCommandLength);
  1245 	writeBuf.FillZ(KModeSenseCommandLength);
  1246 
  1247 	if (pageControl != KDefaultValues)
  1248 		{
  1249 		//check if drive write protected
  1250 		CMassStorageDrive* drive=GetCheckDrive(aLun);
  1251 		if (drive == NULL)
  1252 			{
  1253 			__PRINT(_L("drive == null"));
  1254 			return EFalse;
  1255 			}
  1256 
  1257 		TLocalDriveCapsV4 driveInfo;
  1258 		TInt err = drive->Caps(driveInfo);
  1259 		if (err != KErrNone)
  1260 			{
  1261 			__PRINT(_L("TSenseInfo::ENotReady"));
  1262 			iSenseInfo.SetSense(TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent);
  1263 			return EFalse ;
  1264 			}
  1265 
  1266 		if (driveInfo.iMediaAtt & KMediaAttWriteProtected)
  1267 			{
  1268 			writeBuf[2] = 1<<7;  // set SWP bit at the Device Specific parameters
  1269 			}
  1270 		}
  1271 
  1272 	writeBuf[0]=3;  //Sending only Mode parameter header
  1273 
  1274 	TPtrC8 writeBuf1 = writeBuf;
  1275 
  1276 	iTransport->SetupWriteData(writeBuf1);
  1277 
  1278 	return (iSenseInfo.SenseOk());
  1279 	}
  1280 
  1281