userlibandfileserver/fileserver/smassstorage/scsiprot.cpp
changeset 0 a41df078684a
child 20 597aaf25e343
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     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