os/kernelhwsrv/userlibandfileserver/fileserver/smassstorage/scsiprot.cpp
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/kernelhwsrv/userlibandfileserver/fileserver/smassstorage/scsiprot.cpp	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,1281 @@
     1.4 +// Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
     1.5 +// All rights reserved.
     1.6 +// This component and the accompanying materials are made available
     1.7 +// under the terms of the License "Eclipse Public License v1.0"
     1.8 +// which accompanies this distribution, and is available
     1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
    1.10 +//
    1.11 +// Initial Contributors:
    1.12 +// Nokia Corporation - initial contribution.
    1.13 +//
    1.14 +// Contributors:
    1.15 +//
    1.16 +// Description:
    1.17 +//
    1.18 +
    1.19 +#include "scsiprot.h"
    1.20 +#ifdef MSDC_MULTITHREADED 
    1.21 +#include "rwdrivethread.h"
    1.22 +#endif // MSDC_MULTITHREADED
    1.23 +#include "massstoragedebug.h"
    1.24 +
    1.25 +// Helper macros
    1.26 +#define LBA(x) static_cast<TUint32>((x[3] << 24) | (x[4] << 16) | (x[5] << 8) | x[6])
    1.27 +#define LEN(x) static_cast<TUint16>((x[8] << 8) | x[9])
    1.28 +
    1.29 +
    1.30 +LOCAL_D const TUint KDefaultBlockSize = 0x200;  //default block size for FAT
    1.31 +
    1.32 +LOCAL_D const TUint KUndefinedLun = 0xFFFF;
    1.33 +
    1.34 +LOCAL_D const TUint8 KAllPages = 0x3F;
    1.35 +
    1.36 +LOCAL_D const TUint8 KChangeableValues = 0x1;
    1.37 +LOCAL_D const TUint8 KDefaultValues = 0x2;
    1.38 +
    1.39 +/**
    1.40 +Default constructor for TSenseInfo
    1.41 +*/
    1.42 +TSenseInfo::TSenseInfo()
    1.43 +	: iSenseCode(ENoSense),
    1.44 +	  iAdditional(EAscNull),
    1.45 +	  iQualifier(EAscqNull)
    1.46 +	{}
    1.47 +
    1.48 +
    1.49 +/**
    1.50 +Set sense with no additional info.
    1.51 +
    1.52 +@param aSenseCode sense key
    1.53 +*/
    1.54 +void TSenseInfo::SetSense(TSenseCode aSenseCode)
    1.55 +	{
    1.56 +	iSenseCode = static_cast<TUint8>(aSenseCode);
    1.57 +	iAdditional = EAscNull;
    1.58 +	iQualifier = EAscqNull;
    1.59 +	}
    1.60 +
    1.61 +
    1.62 +/**
    1.63 +Set sense with additional info.
    1.64 +
    1.65 +@param aSenseCode sense key
    1.66 +@param aAdditional additional sense code (ASC) 
    1.67 +*/
    1.68 +void TSenseInfo::SetSense(TSenseCode aSenseCode, TAdditionalCode aAdditional)
    1.69 +
    1.70 +	{
    1.71 +	iSenseCode = static_cast<TUint8>(aSenseCode);
    1.72 +	iAdditional = static_cast<TUint8>(aAdditional);
    1.73 +	iQualifier = EAscqNull;
    1.74 +	}
    1.75 +
    1.76 +
    1.77 +/**
    1.78 +Set sense with additional info and qualifier.
    1.79 +
    1.80 +@param aSenseCode sense key 
    1.81 +@param aAdditional additional sense code (ASC) 
    1.82 +@param aQualifier additional sense code qualifier (ASCQ)
    1.83 +*/
    1.84 +void TSenseInfo::SetSense(TSenseCode aSenseCode,
    1.85 +						  TAdditionalCode aAdditional,
    1.86 +						  TAdditionalSenseCodeQualifier aQualifier)
    1.87 +	{
    1.88 +	iSenseCode = static_cast<TUint8>(aSenseCode);
    1.89 +	iAdditional = static_cast<TUint8>(aAdditional);
    1.90 +	iQualifier = static_cast<TUint8>(aQualifier);
    1.91 +	}
    1.92 +
    1.93 +
    1.94 +//-----------------------------------------------
    1.95 +
    1.96 +/**
    1.97 +Creates the CScsiProtocol object.  Called during controller initialisation.
    1.98 +
    1.99 +@param aDriveManager reference to the drive manager object
   1.100 +*/
   1.101 +CScsiProtocol* CScsiProtocol::NewL(CDriveManager& aDriveManager)
   1.102 +	{
   1.103 +	CScsiProtocol* self = new (ELeave) CScsiProtocol(aDriveManager);
   1.104 +	CleanupStack::PushL(self);
   1.105 +	self->ConstructL();
   1.106 +	CleanupStack::Pop();
   1.107 +	return self;
   1.108 +	}
   1.109 +
   1.110 +/**
   1.111 +c'tor
   1.112 +
   1.113 +@param aDriveManager reference to the drive manager object
   1.114 +*/
   1.115 +CScsiProtocol::CScsiProtocol(CDriveManager& aDriveManager):
   1.116 +	iDriveManager(aDriveManager),
   1.117 +	iLastCommand(EUndefinedCommand),
   1.118 +	iLastLun(KUndefinedLun),
   1.119 +	iMediaWriteSize(KDefaultMediaWriteSize)
   1.120 +	{
   1.121 +	__FNLOG("CScsiProtocol::CScsiProtocol");
   1.122 +
   1.123 +#ifdef USB_TRANSFER_PUBLISHER
   1.124 +	iWriteTransferPublisher = CUsbWriteTransferPublisher::NewL(iBytesWritten);
   1.125 +	iReadTransferPublisher = CUsbReadTransferPublisher::NewL(iBytesRead);
   1.126 +
   1.127 +	for (TUint i = 0; i < KUsbMsMaxDrives; i++)
   1.128 +		{
   1.129 +		iBytesRead[i] = 0;
   1.130 +		iBytesWritten[i] = 0;
   1.131 +		}
   1.132 +#else
   1.133 +	iWriteTransferPublisher = CDriveWriteTransferPublisher::NewL(aDriveManager.iDrives);
   1.134 +	iReadTransferPublisher = CDriveReadTransferPublisher::NewL(aDriveManager.iDrives);
   1.135 +#endif
   1.136 +	}
   1.137 +
   1.138 +
   1.139 +CScsiProtocol::~CScsiProtocol()
   1.140 +	{
   1.141 +	__FNLOG("CScsiProtocol::~CScsiProtocol");
   1.142 +#ifdef MSDC_MULTITHREADED
   1.143 +	__PRINT(_L("Deleting WriteDrive Thread"));
   1.144 +	delete iWriteDriveThread;
   1.145 +	__PRINT(_L("Deleting ReadDrive Thread"));
   1.146 +	delete iReadDriveThread;
   1.147 +#endif // MSDC_MULTITHREADED
   1.148 +
   1.149 +	delete iWriteTransferPublisher;
   1.150 +	delete iReadTransferPublisher;
   1.151 +	}
   1.152 +
   1.153 +
   1.154 +void CScsiProtocol::ConstructL()
   1.155 +	{
   1.156 +	__FNLOG("CScsiProtocol::ConstructL");
   1.157 +#ifdef MSDC_MULTITHREADED
   1.158 +	__PRINT(_L("Creating WriteDrive Thread"));
   1.159 +	iWriteDriveThread = CWriteDriveThread::NewL();
   1.160 +	__PRINT(_L("Creating ReadDrive Thread"));
   1.161 +	iReadDriveThread = CReadDriveThread::NewL();
   1.162 +#endif // MSDC_MULTITHREADED
   1.163 +	}
   1.164 +
   1.165 +
   1.166 +/**
   1.167 +Associates the transport with the protocol. Called during initialisation of the controller.
   1.168 +
   1.169 +@param aTransport pointer to the transport object
   1.170 +*/
   1.171 +void CScsiProtocol::RegisterTransport(MTransportBase* aTransport)
   1.172 +	{
   1.173 +	__FNLOG("CScsiProtocol::RegisterTransport");
   1.174 +	iTransport = aTransport;
   1.175 +	}
   1.176 +
   1.177 +
   1.178 +/**
   1.179 +Called by the Transport when it detects that the USB device is either running
   1.180 +at High Speed or is at least capable of HS operation. The Protocol can use this
   1.181 +information (for instance) to select the optimal write block size to use.
   1.182 +
   1.183 +This function is preferably called before actual MS data transfer operation
   1.184 +starts, and usually only once.
   1.185 +
   1.186 +*/
   1.187 +void CScsiProtocol::ReportHighSpeedDevice()
   1.188 +	{
   1.189 +	__FNLOG("CScsiProtocol::ReportHighSpeedDevice");
   1.190 +	iMediaWriteSize = KHsMediaWriteSize;
   1.191 +	__PRINT1(_L("HS Device reported: SCSI will use %d bytes disk write size"), iMediaWriteSize);
   1.192 +	}
   1.193 +
   1.194 +
   1.195 +TInt CScsiProtocol::SetScsiParameters(TMassStorageConfig aConfig)
   1.196 +	{
   1.197 +	__FNLOG("CScsiProtocol::SetScsiParameters");
   1.198 +	iConfig = aConfig;
   1.199 +	return KErrNone;
   1.200 +	}
   1.201 +
   1.202 +#ifdef MSDC_MULTITHREADED
   1.203 +
   1.204 +void CScsiProtocol::ProcessWriteComplete (TUint8* aAddress, TAny* aPtr)
   1.205 +	{
   1.206 +	((CScsiProtocol*)aPtr)->iTransport->ProcessReadData(aAddress);
   1.207 +	}
   1.208 +
   1.209 +void CScsiProtocol::InitializeBufferPointers(TPtr8& aDes1, TPtr8& aDes2) // Todo Change name later - InitializeReadBufferSomething
   1.210 +	{
   1.211 +	iReadDriveThread->iThreadContext->iBuffer.SetUpReadBuf(aDes1, aDes2);
   1.212 +	}
   1.213 +#endif
   1.214 +
   1.215 +/**
   1.216 +Called by the transport layer when a packet is available for decoding.
   1.217 +If an error occurs, the sense code is updated and EFalse is returned.
   1.218 +
   1.219 +@param aData
   1.220 +
   1.221 +@return  ETrue if command was decoded and executed successfully
   1.222 +*/
   1.223 +TBool CScsiProtocol::DecodePacket(TPtrC8& aData, TUint aLun)
   1.224 +	{
   1.225 +	__FNLOG("CScsiProtocol::DecodePacket");
   1.226 +
   1.227 +	TUint8 command = aData[1];
   1.228 +
   1.229 +	if (command != ERequestSense)
   1.230 +		{
   1.231 +		iSenseInfo.SetSense(TSenseInfo::ENoSense);
   1.232 +		}
   1.233 +
   1.234 +	__PRINT2(_L("command = 0x%x lun=%d"), command, aLun);
   1.235 +	switch (command)
   1.236 +		{
   1.237 +		case ETestUnitReady:
   1.238 +			HandleUnitReady(aLun);
   1.239 +			break;
   1.240 +
   1.241 +		case ERequestSense:
   1.242 +			HandleRequestSense(aData);
   1.243 +			break;
   1.244 +
   1.245 +		case EInquiry:
   1.246 +			HandleInquiry(aData, aLun);
   1.247 +			break;
   1.248 +
   1.249 +		case EModeSense:
   1.250 +			HandleModeSense(aData, aLun);
   1.251 +			break;
   1.252 +
   1.253 +		case EStartStopUnit:
   1.254 +			HandleStartStopUnit(aData, aLun);
   1.255 +			break;
   1.256 +
   1.257 +		case EPreventMediaRemoval:
   1.258 +			HandlePreventMediaRemoval(aData, aLun);
   1.259 +			break;
   1.260 +
   1.261 +		case EReadCapacity:
   1.262 +			HandleReadCapacity(aData, aLun);
   1.263 +			break;
   1.264 +
   1.265 +		case ERead10:
   1.266 +			HandleRead10(aData, aLun);
   1.267 +			break;
   1.268 +
   1.269 +		case EWrite10:
   1.270 +			HandleWrite10(aData,aLun);
   1.271 +			break;
   1.272 +
   1.273 +		case EVerify10:
   1.274 +			HandleVerify10(aData, aLun);
   1.275 +			break;
   1.276 +
   1.277 +		case EReadFormatCapacities:
   1.278 +			HandleReadFormatCapacities(aLun);
   1.279 +			break;
   1.280 +
   1.281 +		default:
   1.282 +			iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidCmdCode);
   1.283 +		}
   1.284 +	__PRINT1(_L("DecodePacket result = %d"), iSenseInfo.SenseOk());
   1.285 +	return(iSenseInfo.SenseOk());
   1.286 +	}
   1.287 +
   1.288 +
   1.289 +/**
   1.290 +Checks if drive ready
   1.291 +
   1.292 +@param aLun Logic unit number 
   1.293 +@return pointer to drive correspondent to LUN if drive mounted and ready, NULL otherwise
   1.294 +*/
   1.295 +CMassStorageDrive* CScsiProtocol::GetCheckDrive(TUint aLun)
   1.296 +	{
   1.297 +	__FNLOG("CScsiProtocol::GetCheckDrive");
   1.298 +	TInt err=KErrNone;
   1.299 +
   1.300 +#ifdef MSDC_MULTITHREADED
   1.301 +	// check for deferred errors
   1.302 +	if (iWriteDriveThread->DeferredError())
   1.303 +		{
   1.304 +		iWriteDriveThread->ClearDeferredError();
   1.305 +		iDeferredSenseInfo.SetSense(TSenseInfo::EMediumError);
   1.306 +		return NULL;
   1.307 +		}
   1.308 +
   1.309 +#endif
   1.310 +
   1.311 +	CMassStorageDrive* drive= iDriveManager.Drive(aLun, err);
   1.312 +
   1.313 +	if (err !=KErrNone || drive == NULL)
   1.314 +		{
   1.315 +		__PRINT(_L("No drive available\n"));
   1.316 +		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::ELuNotSupported);
   1.317 +		return NULL;
   1.318 +		}
   1.319 +
   1.320 +	CMassStorageDrive::TMountState mountState = drive->MountState();
   1.321 +
   1.322 +	if (mountState == CMassStorageDrive::EDisconnected || mountState == CMassStorageDrive::EConnecting)
   1.323 +		{
   1.324 +		__PRINT(_L("Drive disconnected\n"));
   1.325 +		iSenseInfo.SetSense(TSenseInfo::ENotReady,
   1.326 +							TSenseInfo::EMediaNotPresent);
   1.327 +		return NULL;
   1.328 +		}
   1.329 +
   1.330 +	CMassStorageDrive::TDriveState state = drive->CheckDriveState();
   1.331 +	if (state == CMassStorageDrive::EMediaNotPresent || state == CMassStorageDrive::ELocked)
   1.332 +		{
   1.333 +		__PRINT1(_L("Media not present or locked. (state =0x%X)\n"),state);
   1.334 +		iSenseInfo.SetSense(TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent);
   1.335 +		return NULL;
   1.336 +		}
   1.337 +
   1.338 +	if (drive->IsMediaChanged(ETrue))  //reset "media changed" status
   1.339 +		{
   1.340 +		__PRINT(_L("Media was changed\n"));
   1.341 +		// SAM-2 Section 5.9.5 Unit Attention Condition
   1.342 +		iSenseInfo.SetSense(TSenseInfo::EUnitAttention, TSenseInfo::ENotReadyToReadyChange);
   1.343 +		iDriveManager.Connect(aLun);   //publish event to USB app
   1.344 +		return NULL;
   1.345 +		}
   1.346 +
   1.347 +	if (mountState == CMassStorageDrive::EDisconnecting)
   1.348 +		{
   1.349 +		__PRINT(_L("Drive disconnecting\n"));
   1.350 +		iSenseInfo.SetSense(TSenseInfo::ENotReady,
   1.351 +							TSenseInfo::EMediaNotPresent);
   1.352 +		return NULL;
   1.353 +		}
   1.354 +
   1.355 +	return drive;
   1.356 +	}
   1.357 +
   1.358 +
   1.359 +/**
   1.360 +Command Parser for the UNIT READY command (0x00)
   1.361 +
   1.362 +@param aLun Logic unit number 
   1.363 +@return ETrue if successful, 
   1.364 +*/
   1.365 +TBool CScsiProtocol::HandleUnitReady(TUint aLun)
   1.366 +	{
   1.367 +	__FNLOG("CScsiProtocol::HandleUnitReady");
   1.368 +#ifdef MSDC_MULTITHREADED
   1.369 +	iWriteDriveThread->WaitForWriteEmpty();
   1.370 +#endif
   1.371 +	return GetCheckDrive(aLun) ? (TBool)ETrue : (TBool)EFalse;
   1.372 +	}
   1.373 +
   1.374 +
   1.375 +/**
   1.376 +Command Parser for the REQUEST SENSE command (0x03)
   1.377 +
   1.378 +@return ETrue if successful, 
   1.379 +*/
   1.380 +TBool CScsiProtocol::HandleRequestSense(TPtrC8& aData)
   1.381 +	{
   1.382 +	__FNLOG("CScsiProtocol::HandleRequestSense");
   1.383 +	TUint length = aData[5];
   1.384 +	__PRINT1(_L("length = %d\n"), length);
   1.385 +	
   1.386 +	TPtr8 writeBuf(NULL, 0);
   1.387 +	iTransport->GetCommandBufPtr(writeBuf, KRequestSenseCommandLength);
   1.388 +	writeBuf.FillZ(KRequestSenseCommandLength);
   1.389 +
   1.390 +	TSenseInfo* senseInfo;
   1.391 +#ifdef MSDC_MULTITHREADED
   1.392 +	if (!iDeferredSenseInfo.SenseOk())
   1.393 +		{
   1.394 +		writeBuf[00] = 0x71; //(deferred errors)
   1.395 +		senseInfo = &iDeferredSenseInfo;
   1.396 +		}
   1.397 +	else
   1.398 +		{
   1.399 +		writeBuf[00] = 0x70; //(current errors)
   1.400 +		senseInfo = &iSenseInfo;
   1.401 +		}
   1.402 +#else
   1.403 +	senseInfo = &iSenseInfo;
   1.404 +	writeBuf[00] = 0x70; //(current errors)
   1.405 +#endif
   1.406 +
   1.407 +	writeBuf[02] = static_cast<TUint8>(senseInfo->iSenseCode & 0x0F);
   1.408 +
   1.409 +	writeBuf[12] = senseInfo->iAdditional;
   1.410 +	writeBuf[13] = senseInfo->iQualifier;
   1.411 +	if (length<18 && length >=8) 
   1.412 +		{
   1.413 +		writeBuf.SetLength(length);  //length of response code data
   1.414 +		writeBuf[07] = TUint8(length - 8);  //additional sence length
   1.415 +		}
   1.416 +	else if (length >= KRequestSenseCommandLength)
   1.417 +		{
   1.418 +		writeBuf[07] = KRequestSenseCommandLength - 8;	// we have max 18 byte to send
   1.419 +		}
   1.420 +
   1.421 +	__PRINT4(_L("Response=0x%x Sense=0x%x, Additional=0x%x, Qualifier=0x%x\n"),
   1.422 +				writeBuf[0], writeBuf[02], writeBuf[12], writeBuf[13]);
   1.423 + 
   1.424 +	TPtrC8 writeBuf1 = writeBuf.Left(length);
   1.425 +
   1.426 +	iTransport->SetupWriteData(writeBuf1);
   1.427 +
   1.428 +	// clear the sense info
   1.429 +	iSenseInfo.SetSense(TSenseInfo::ENoSense);
   1.430 +
   1.431 +#ifdef MSDC_MULTITHREADED
   1.432 +	iDeferredSenseInfo.SetSense(TSenseInfo::ENoSense);
   1.433 +#endif
   1.434 +
   1.435 +	return ETrue;
   1.436 +	}
   1.437 +
   1.438 +
   1.439 +/**
   1.440 +Command Parser for the INQUIRY command (0x12)
   1.441 +
   1.442 +@param aLun Logic unit number 
   1.443 +@return ETrue if successful, 
   1.444 +*/
   1.445 +TBool CScsiProtocol::HandleInquiry(TPtrC8& aData, TUint  aLun )
   1.446 +	{
   1.447 +	__FNLOG("CScsiProtocol::HandleInquiry");
   1.448 +
   1.449 +	TBool cmdDt = aData[2] & 0x2;
   1.450 +	TBool evpd  = aData[2] & 0x1;
   1.451 +	TUint8 page = aData[3];
   1.452 +	if (cmdDt || evpd || page || aLun >= KUsbMsMaxDrives)
   1.453 +		{
   1.454 +		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb); 
   1.455 +		return EFalse;
   1.456 +		}
   1.457 +
   1.458 +	TPtr8 writeBuf(NULL, 0);
   1.459 +	iTransport->GetCommandBufPtr(writeBuf, KInquiryCommandLength);
   1.460 +	writeBuf.FillZ(KInquiryCommandLength);
   1.461 +
   1.462 +	writeBuf[1] = 0x80;	// MSB: RMB : Removable
   1.463 +	writeBuf[3] = 0x02;	// AERC, TrmTsk, NormACA, Response Data Format
   1.464 +	writeBuf[4] = 0x1F;	// Additional Length
   1.465 +
   1.466 +	TPtr8 vendorId(&writeBuf[8], 8, 8);		// Vendor ID (Vendor Specific/Logged by T10)
   1.467 +	vendorId.Fill(' ', 8);
   1.468 +	vendorId.Copy(iConfig.iVendorId);
   1.469 +
   1.470 +	TPtr8 productId(&writeBuf[16], 16, 16);	// Product ID (Vendor Specific)
   1.471 +	productId.Fill(' ', 16);
   1.472 +	productId.Copy(iConfig.iProductId);
   1.473 +
   1.474 +	TPtr8 productRev(&writeBuf[32], 4, 4);		// Product Revision Level (Vendor Specific)
   1.475 +	productRev.Fill(' ', 4);
   1.476 +	productRev.Copy(iConfig.iProductRev);
   1.477 +
   1.478 +    TUint length = aData[5];
   1.479 +
   1.480 +	TPtrC8 writeBuf1 = writeBuf.Left(length);
   1.481 +	iTransport->SetupWriteData(writeBuf1);
   1.482 +
   1.483 +	iSenseInfo.SetSense(TSenseInfo::ENoSense); 
   1.484 +	return ETrue;
   1.485 +	}
   1.486 +
   1.487 +
   1.488 +/**
   1.489 + Command Parser for the START STOP UNIT command (0x1B)
   1.490 + 
   1.491 + @param aData command data (started form position 1)
   1.492 + @param aLun Logic unit number 
   1.493 + @return ETrue if successful, TFalse otherwise
   1.494 + */
   1.495 +TBool CScsiProtocol::HandleStartStopUnit(TPtrC8& aData, TUint aLun)
   1.496 +	{
   1.497 +	__FNLOG("CScsiProtocol::HandleStartStopUnit");
   1.498 +
   1.499 +	const TUint8 KStartMask = 0x01;
   1.500 +	const TUint8 KImmedMask = 0x01;
   1.501 +	const TUint8 KLoejMask = 0x02;
   1.502 +
   1.503 +	TBool immed = aData[2] & KImmedMask ? (TBool)ETrue : (TBool)EFalse;
   1.504 +	TBool start = aData[5] & KStartMask ? (TBool)ETrue : (TBool)EFalse;
   1.505 +	TBool loej = aData[5] & KLoejMask ? (TBool)ETrue : (TBool)EFalse;
   1.506 +
   1.507 +	__PRINT2(_L("Data %X %X\n"), aData[2], aData[5]);
   1.508 +	__PRINT1(_L("IMMED = %d\n"), immed);
   1.509 +	__PRINT1(_L("START = %d\n"), start);
   1.510 +
   1.511 +	__PRINT1(_L("LOEJ = %d\n"), loej);
   1.512 +
   1.513 +	TInt err(KErrNone);
   1.514 +	if (loej)
   1.515 +		{
   1.516 +		if(start)	//Start unit
   1.517 +			{
   1.518 +			err = iDriveManager.Connect(aLun);
   1.519 +			__PRINT(_L("Load media\n"));
   1.520 +
   1.521 +#ifdef USB_TRANSFER_PUBLISHER
   1.522 +			iBytesRead[aLun] = 0;
   1.523 +			iBytesWritten[aLun] = 0;
   1.524 +#endif
   1.525 +			// publish the initial values
   1.526 +			iWriteTransferPublisher->DoPublishDataTransferredEvent();
   1.527 +			iReadTransferPublisher->DoPublishDataTransferredEvent();
   1.528 +			}
   1.529 +		else		//Stop unit 
   1.530 +			{
   1.531 +			iDriveManager.SetCritical(aLun, EFalse);
   1.532 +			err = iDriveManager.Disconnect(aLun);
   1.533 +			__PRINT(_L("Unload media\n"));
   1.534 +			}
   1.535 +		}
   1.536 +
   1.537 +	if (err !=KErrNone)  //actually we have error here only if the LUN is incorrect 
   1.538 +		{
   1.539 +		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::ELuNotSupported);
   1.540 +		return EFalse;
   1.541 +		}
   1.542 +	if (immed)
   1.543 +		{
   1.544 +		return ETrue;
   1.545 +		}
   1.546 +
   1.547 +	CMassStorageDrive* drive= iDriveManager.Drive(aLun, err);
   1.548 +
   1.549 +	if (err !=KErrNone || drive == NULL)
   1.550 +		{
   1.551 +		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::ELuNotSupported);
   1.552 +		return EFalse;
   1.553 +		}
   1.554 +
   1.555 +	TInt  timeLeft (20);   // 1 sec timeout
   1.556 +	CMassStorageDrive::TMountState mountState;
   1.557 +
   1.558 +	do 
   1.559 +		{
   1.560 +		User::After(1000 * 50);		// 50 mSec
   1.561 +		--timeLeft;
   1.562 +		mountState = drive->MountState();
   1.563 +
   1.564 +		if ((!start && mountState != CMassStorageDrive::EConnected)
   1.565 +			 ||
   1.566 +			 (start &&
   1.567 +				(mountState == CMassStorageDrive::EDisconnecting || 
   1.568 +				mountState == CMassStorageDrive::EConnected))
   1.569 +			)
   1.570 +			{
   1.571 +			return ETrue;
   1.572 +			}
   1.573 +		} while (timeLeft>0);
   1.574 +
   1.575 +	//timeout happend
   1.576 +	iSenseInfo.SetSense(TSenseInfo::ENotReady,
   1.577 +						TSenseInfo::EAscLogicalUnitDoesNotRespondToSelection);
   1.578 +	return EFalse;
   1.579 +	}
   1.580 +
   1.581 +
   1.582 +/**
   1.583 +Command Parser for the PREVENT/ALLOW MEDIA REMOVAL command (0x1E)
   1.584 +
   1.585 +@param aData command data (started form position 1)
   1.586 +@param aLun Logic unit number 
   1.587 +@return ETrue if successful.
   1.588 +*/
   1.589 +TBool CScsiProtocol::HandlePreventMediaRemoval(TPtrC8& aData, TUint aLun)
   1.590 +	{
   1.591 +	__FNLOG("CScsiProtocol::HandlePreventMediaRemoval");
   1.592 +	CMassStorageDrive* drive=GetCheckDrive(aLun);
   1.593 +
   1.594 +	if (drive == NULL)
   1.595 +		{
   1.596 +		return EFalse;
   1.597 +		}
   1.598 +
   1.599 +	TInt prevent = aData[5] & 0x01;
   1.600 +	__PRINT1(_L("prevent = %d\n"), prevent);
   1.601 +	iDriveManager.SetCritical(aLun, prevent);
   1.602 +
   1.603 +	return ETrue;
   1.604 +	}
   1.605 +
   1.606 +
   1.607 +/** Cancel active state, Invoked by transnport when it stops */
   1.608 +TInt CScsiProtocol::Cancel()
   1.609 +	{
   1.610 +	iDriveManager.SetCritical(CDriveManager::KAllLuns, EFalse);
   1.611 +	return KErrNone;
   1.612 +	}
   1.613 +
   1.614 +
   1.615 +TBool CScsiProtocol::HandleReadFormatCapacities(TUint aLun)
   1.616 +/**
   1.617 + * Command Parser for the READ FORMAT CAPACITIES command (0x23)
   1.618 + *
   1.619 + * @return ETrue if successful, else a standard Symbian OS error code.
   1.620 + */
   1.621 +	{
   1.622 +	__FNLOG("CScsiProtocol::HandleReadFormatCapacities");
   1.623 +
   1.624 +	CMassStorageDrive* drive=GetCheckDrive(aLun);
   1.625 +
   1.626 +	if (drive == NULL)
   1.627 +		{
   1.628 +		return EFalse;
   1.629 +		}
   1.630 +
   1.631 +	TLocalDriveCapsV4 driveInfo;
   1.632 +
   1.633 +	TInt err = drive->Caps(driveInfo);
   1.634 +
   1.635 +	if(err != KErrNone)
   1.636 +		{
   1.637 +		__PRINT1(_L("Can't obtain drive Caps. Err=%d \n"),err);
   1.638 +		iSenseInfo.SetSense(TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent);
   1.639 +		return EFalse;
   1.640 +		}
   1.641 +
   1.642 +	TInt64 driveBlocks = (driveInfo.iDriveAtt & KDriveAttLogicallyRemovable) ? driveInfo.iSize : driveInfo.MediaSizeInBytes();
   1.643 +	driveBlocks /= MAKE_TINT64(0, KDefaultBlockSize);
   1.644 +
   1.645 +	TPtr8 writeBuf(NULL, 0);
   1.646 +	iTransport->GetCommandBufPtr(writeBuf, KReadFormatCapacitiesCommandLength);
   1.647 +	writeBuf.FillZ(KReadFormatCapacitiesCommandLength);
   1.648 +
   1.649 +	writeBuf[3] = 0x08;	// Capacity List Length
   1.650 +
   1.651 +	TUint32 numBlocks = I64LOW(driveBlocks);
   1.652 +
   1.653 +	writeBuf[4] = static_cast<TUint8>((numBlocks & 0xFF000000) >> 24);	// Number of blocks
   1.654 +	writeBuf[5] = static_cast<TUint8>((numBlocks & 0x00FF0000) >> 16);	//
   1.655 +	writeBuf[6] = static_cast<TUint8>((numBlocks & 0x0000FF00) >> 8);	//
   1.656 +	writeBuf[7] = static_cast<TUint8>((numBlocks & 0x000000FF));		//
   1.657 +
   1.658 +	writeBuf[8] = 0x02;	// Formatted size
   1.659 +
   1.660 +	writeBuf[9]  = 0x00;	// 512 Byte Blocks
   1.661 +	writeBuf[10] = 0x02;	// 
   1.662 +	writeBuf[11] = 0x00;	// 
   1.663 +
   1.664 +	TPtrC8 writeBuf1 = writeBuf;
   1.665 +
   1.666 +	iTransport->SetupWriteData(writeBuf1);
   1.667 +
   1.668 +	return ETrue;
   1.669 +	}
   1.670 +
   1.671 +
   1.672 +/**
   1.673 +Command Parser for the READ CAPACITY(10) command (0x25)
   1.674 +
   1.675 +@param aData command data (started form position 1)
   1.676 +@param aLun Logic unit number 
   1.677 +@return ETrue if successful.
   1.678 +*/
   1.679 +TBool CScsiProtocol::HandleReadCapacity(TPtrC8& aData, TUint aLun)
   1.680 +	{
   1.681 +	__FNLOG("CScsiProtocol::HandleReadCapacity");
   1.682 +	CMassStorageDrive* drive=GetCheckDrive(aLun);
   1.683 +
   1.684 +	if (drive == NULL)
   1.685 +		{
   1.686 +		return EFalse;
   1.687 +		}
   1.688 +
   1.689 +	TInt pmi = aData[9] & 0x01;
   1.690 +	TInt lba = aData[3] | aData[4] | aData[5] | aData[6];
   1.691 +
   1.692 +	if (pmi || lba)   //do not support partial medium indicator
   1.693 +		{
   1.694 +		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
   1.695 +		return EFalse;
   1.696 +		} 
   1.697 +
   1.698 +	TLocalDriveCapsV4 driveInfo;
   1.699 +
   1.700 +	TInt err = drive->Caps(driveInfo);
   1.701 +
   1.702 +	if(err != KErrNone)
   1.703 +		{
   1.704 +		__PRINT1(_L("Can't obtain drive Caps. Err=%d \n"),err);
   1.705 +		iSenseInfo.SetSense(TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent);
   1.706 +		return EFalse;
   1.707 +		}
   1.708 +
   1.709 +	TInt64 driveBlocks = 0;
   1.710 +	if (driveInfo.iDriveAtt & KDriveAttLogicallyRemovable)
   1.711 +		{
   1.712 +		// Partition Access only 
   1.713 +		driveBlocks = driveInfo.iSize / MAKE_TINT64(0, KDefaultBlockSize);
   1.714 +		}
   1.715 +	else
   1.716 +		{
   1.717 +		// whole Media Access
   1.718 +		driveBlocks = driveInfo.MediaSizeInBytes() / MAKE_TINT64(0, KDefaultBlockSize) - 1;
   1.719 +		}
   1.720 +	
   1.721 +
   1.722 +	TPtr8 writeBuf(NULL, 0);
   1.723 +	iTransport->GetCommandBufPtr(writeBuf, KReadCapacityCommandLength);
   1.724 +	writeBuf.FillZ(KReadCapacityCommandLength);
   1.725 +
   1.726 +	if (I64HIGH(driveBlocks) == 0)
   1.727 +		{
   1.728 +		TUint32 numBlocks = I64LOW(driveBlocks);
   1.729 +
   1.730 +		__PRINT2(_L("Block size=%d, NumBlocks=%d\n"), KDefaultBlockSize, numBlocks);
   1.731 +		writeBuf[0] = static_cast<TUint8>((numBlocks & 0xFF000000) >> 24);	// Number of blocks
   1.732 +		writeBuf[1] = static_cast<TUint8>((numBlocks & 0x00FF0000) >> 16);
   1.733 +		writeBuf[2] = static_cast<TUint8>((numBlocks & 0x0000FF00) >> 8);
   1.734 +		writeBuf[3] = static_cast<TUint8>((numBlocks & 0x000000FF));
   1.735 +		}
   1.736 +	else   
   1.737 +		{
   1.738 +		writeBuf[0] = writeBuf[1] = writeBuf[2] = writeBuf[3] = 0xFF;  // indicate that size more then )0xFFFFFFFF
   1.739 +		}
   1.740 +
   1.741 +	writeBuf[4] = static_cast<TUint8>((KDefaultBlockSize & 0xFF000000) >> 24);	// Block Size
   1.742 +	writeBuf[5] = static_cast<TUint8>((KDefaultBlockSize & 0x00FF0000) >> 16);
   1.743 +	writeBuf[6] = static_cast<TUint8>((KDefaultBlockSize & 0x0000FF00) >> 8);
   1.744 +	writeBuf[7] = static_cast<TUint8>((KDefaultBlockSize & 0x000000FF));
   1.745 +
   1.746 +	TPtrC8 writeBuf1 = writeBuf;
   1.747 +	iTransport->SetupWriteData(writeBuf1);
   1.748 +
   1.749 +	return KErrNone;
   1.750 +	}
   1.751 +
   1.752 +
   1.753 +/**
   1.754 +Command Parser for the READ10 command (0x28)
   1.755 +
   1.756 +@param aData command data (started form position 1)
   1.757 +@param aLun Logic unit number
   1.758 +@return ETrue if successful.
   1.759 +*/
   1.760 +TBool CScsiProtocol::HandleRead10(TPtrC8& aData, TUint aLun)
   1.761 +	{
   1.762 +	__FNLOG("CScsiProtocol::HandleRead10");
   1.763 +	CMassStorageDrive* drive = GetCheckDrive(aLun);
   1.764 +	if (drive == NULL)
   1.765 +		{
   1.766 +		return EFalse;
   1.767 +		}
   1.768 +	TInt rdProtect = aData[2] >> 5;
   1.769 +	if (rdProtect)
   1.770 +		{
   1.771 +		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
   1.772 +		return EFalse;
   1.773 +		}
   1.774 +
   1.775 +	const TUint32 lba = LBA(aData);
   1.776 +	const TUint16 len = LEN(aData);
   1.777 +
   1.778 +	__PRINT2(_L("READ(10) : LBA = 0x%x, Length = %d  (blocks)\n"), lba, len);
   1.779 +
   1.780 +	if (!len)
   1.781 +		{
   1.782 +		return ETrue; // do nothing - this is not an error
   1.783 +		}
   1.784 +
   1.785 +	TLocalDriveCapsV4 driveInfo;
   1.786 +	TInt err = drive->Caps(driveInfo);
   1.787 +	if (err != KErrNone)
   1.788 +		{
   1.789 +		__PRINT1(_L("Can't obtain drive Caps. Err=%d \n"), err);
   1.790 +		iSenseInfo.SetSense(TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent);
   1.791 +		return EFalse;
   1.792 +		}
   1.793 +
   1.794 +	const TInt64 bOffset = MAKE_TINT64(0, lba) * KDefaultBlockSize;
   1.795 +	const TInt bLength = len * KDefaultBlockSize;
   1.796 +	const TInt64 theEnd = bOffset + MAKE_TINT64(0, bLength);
   1.797 +	const TInt64 mediaSize = (driveInfo.iDriveAtt & KDriveAttLogicallyRemovable) ? driveInfo.iSize : driveInfo.MediaSizeInBytes() ;
   1.798 +	
   1.799 +	if (theEnd > mediaSize)  //check if media big enough for this request
   1.800 +		{
   1.801 +		__PRINT(_L("err - Request ends out of media\n"));
   1.802 +		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::ELbaOutOfRange);
   1.803 +		return EFalse;
   1.804 +		}
   1.805 +
   1.806 +#ifdef MSDC_MULTITHREADED
   1.807 +	iWriteDriveThread->WaitForWriteEmpty();
   1.808 +
   1.809 +	// check if our buffer can hold requested data
   1.810 +	if (iReadDriveThread->iThreadContext->MaxBufferLength() < bLength)
   1.811 +		{
   1.812 +		__PRINT(_L("err - Buffer too small\n"));
   1.813 +		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
   1.814 +		return EFalse;
   1.815 +		}
   1.816 +
   1.817 +    // Optimisation note : If the host is reading from sectors it just wrote to,
   1.818 +    // then we have to force a cache-miss so that the real data is read from the
   1.819 +    // drive. It would be possible to service the read from the write buffers, 
   1.820 +    // but as the host is probably trying to verify the write data, we don't do 
   1.821 +    // that for now. 
   1.822 +	if (!iReadDriveThread->ReadDriveData(drive, bOffset, bLength, iWriteDriveThread->IsRecentlyWritten(bOffset,bLength)))
   1.823 +		{
   1.824 +		iSenseInfo.SetSense(TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent);
   1.825 +		return EFalse;
   1.826 +		}
   1.827 +
   1.828 +	iWriteDriveThread->SetCommandWrite10(EFalse);
   1.829 +	TBlockDesc* &desc = iReadDriveThread->iThreadContext->iBuffer.iDescReadPtr;
   1.830 +	TPtrC8 writeBuf1 = desc->iBuf;
   1.831 +#else
   1.832 +	
   1.833 +	TPtr8 writeBuf(NULL, 0);
   1.834 +	iTransport->GetReadDataBufPtr(writeBuf);
   1.835 +	// check if our buffer can hold requested data
   1.836 +	if (writeBuf.MaxLength() < bLength)
   1.837 +		{
   1.838 +		__PRINT(_L("err - Buffer too small\n"));
   1.839 +		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
   1.840 +		return EFalse;
   1.841 +		}
   1.842 +
   1.843 +	err = drive->Read(bOffset, bLength, writeBuf, drive->IsWholeMediaAccess());
   1.844 +
   1.845 +	if (err != KErrNone)
   1.846 +		{
   1.847 +		__PRINT1(_L("Read failed, err=%d\n"), err);
   1.848 +		iSenseInfo.SetSense(TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent);
   1.849 +		return EFalse;
   1.850 +		}
   1.851 +
   1.852 +	TPtrC8 writeBuf1 = writeBuf;
   1.853 +#endif // MSDC_MULTITHREADED
   1.854 +#ifdef USB_TRANSFER_PUBLISHER
   1.855 +	iBytesRead[aLun] += writeBuf1.Length();
   1.856 +#endif
   1.857 +	iReadTransferPublisher->StartTimer();
   1.858 +
   1.859 +	// Set up data write to the host
   1.860 +	iTransport->SetupWriteData(writeBuf1);
   1.861 +
   1.862 +	return ETrue;
   1.863 +	}
   1.864 +
   1.865 +
   1.866 +/**
   1.867 +Command Parser for the WRITE(10) command (0x2A)
   1.868 +
   1.869 +@param aData command data (started form position 1)
   1.870 +@param aLun Logic unit number
   1.871 +@return ETrue if successful.
   1.872 +*/
   1.873 +TBool CScsiProtocol::HandleWrite10(TPtrC8& aData, TUint aLun)
   1.874 +	{
   1.875 +	__FNLOG("CScsiProtocol::HandleWrite10");
   1.876 +	CMassStorageDrive* drive = GetCheckDrive(aLun);
   1.877 +	if (drive == NULL)
   1.878 +		{
   1.879 +		return EFalse;
   1.880 +		}
   1.881 +	TInt wrProtect = aData[2] >> 5;
   1.882 +	if (wrProtect)
   1.883 +		{
   1.884 +		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
   1.885 +		return EFalse;
   1.886 +		}
   1.887 +
   1.888 +	const TUint32 lba = LBA(aData);
   1.889 +	const TUint16 len = LEN(aData);
   1.890 +	__PRINT2(_L("WRITE(10) : LBA = 0x%x, Length = %d (blocks)\n"), lba, len);
   1.891 +	if (!len)
   1.892 +		{
   1.893 +		return ETrue; // do nothing - this is not an error
   1.894 +		}
   1.895 +
   1.896 +	TLocalDriveCapsV4 driveInfo;
   1.897 +	TInt err = drive->Caps(driveInfo);
   1.898 +	if (err != KErrNone)
   1.899 +		{
   1.900 +		__PRINT1(_L("Can't obtain drive Caps. Err=%d \n"), err);
   1.901 +		iSenseInfo.SetSense(TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent);
   1.902 +		return EFalse;
   1.903 +		}
   1.904 +	if (driveInfo.iMediaAtt & KMediaAttWriteProtected ||
   1.905 +		driveInfo.iMediaAtt & KMediaAttLocked)
   1.906 +		{
   1.907 +		iSenseInfo.SetSense(TSenseInfo::EDataProtection, TSenseInfo::EWriteProtected);
   1.908 +		return EFalse;
   1.909 +		}
   1.910 +
   1.911 +	const TInt64 bOffset = MAKE_TINT64(0, lba) * KDefaultBlockSize;
   1.912 +	iBytesRemain = len * KDefaultBlockSize;
   1.913 +	const TInt64 theEnd = bOffset + MAKE_TINT64(0, iBytesRemain);
   1.914 +	const TInt64 mediaSize = (driveInfo.iDriveAtt & KDriveAttLogicallyRemovable) ? driveInfo.iSize : driveInfo.MediaSizeInBytes() ;
   1.915 +
   1.916 +	if (theEnd > mediaSize)  //check if media big enough for this request
   1.917 +		{
   1.918 +		__PRINT(_L("err - Request ends out of media\n"));
   1.919 +		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::ELbaOutOfRange);
   1.920 +		return EFalse;
   1.921 +		}
   1.922 +
   1.923 +#ifdef MSDC_MULTITHREADED
   1.924 +	iWriteDriveThread->SetCommandWrite10(ETrue);
   1.925 +#endif
   1.926 +
   1.927 +	// Set up the first request for data from the host - either
   1.928 +	// KMaxBufSize or the entire transfer length, whichever is smallest.
   1.929 +	TUint thisLength = (iBytesRemain > KMaxBufSize) ? KMaxBufSize : iBytesRemain;
   1.930 +	thisLength = (thisLength > iMediaWriteSize) ? iMediaWriteSize : thisLength;
   1.931 +
   1.932 +	iOffset = bOffset;
   1.933 +	iLastCommand = EWrite10;
   1.934 +	iLastLun = aLun;
   1.935 +
   1.936 +	iWriteTransferPublisher->StartTimer();
   1.937 +	iTransport->SetupReadData(thisLength);
   1.938 +
   1.939 +	return ETrue;
   1.940 +	}
   1.941 +
   1.942 +
   1.943 +/**
   1.944 +Command Parser for the VERIFY(10) command (0x2F)
   1.945 +
   1.946 +@param aData command data (started form position 1)
   1.947 +@param aLun Logic unit number
   1.948 +@return ETrue if successful.
   1.949 +*/
   1.950 +TBool CScsiProtocol::HandleVerify10(TPtrC8& aData, TUint aLun)
   1.951 +	{
   1.952 +	__FNLOG("CScsiProtocol::HandleVerify10");
   1.953 +	CMassStorageDrive* drive = GetCheckDrive(aLun);
   1.954 +	if (drive == NULL)
   1.955 +		{
   1.956 +		return EFalse;
   1.957 +		}
   1.958 +
   1.959 +	TInt vrProtect = aData[2] >> 5;
   1.960 +	if (vrProtect)
   1.961 +		{
   1.962 +		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
   1.963 +		return EFalse;
   1.964 +		}
   1.965 +
   1.966 +	const TUint32 lba = LBA(aData);
   1.967 +	const TUint16 len = LEN(aData);
   1.968 +	__PRINT2(_L("VERIFY(10) : LBA = %d, Length = %d  (blocks)\n"), lba, len);
   1.969 +
   1.970 +	TInt bytChk = aData[2] & 0x02;
   1.971 +	if (!len)
   1.972 +		{
   1.973 +		return ETrue; // do nothing - this is not an error
   1.974 +		}
   1.975 +
   1.976 +	TLocalDriveCapsV4 driveInfo;
   1.977 +	TInt err = drive->Caps(driveInfo);
   1.978 +	if (err != KErrNone)
   1.979 +		{
   1.980 +		__PRINT1(_L("Can't obtain drive Caps. Err=%d \n"), err);
   1.981 +		iSenseInfo.SetSense(TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent);
   1.982 +		return EFalse;
   1.983 +		}
   1.984 +
   1.985 +	const TInt64 bOffset = MAKE_TINT64(0, lba) * KDefaultBlockSize;
   1.986 +	const TInt bLength = len * KDefaultBlockSize;
   1.987 +	const TInt64 theEnd = bOffset + MAKE_TINT64(0, bLength);
   1.988 +	const TInt64 mediaSize = (driveInfo.iDriveAtt & KDriveAttLogicallyRemovable) ? driveInfo.iSize : driveInfo.MediaSizeInBytes() ;
   1.989 +
   1.990 +	// check if media big enough for this request
   1.991 +	if (theEnd > mediaSize)
   1.992 +		{
   1.993 +		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::ELbaOutOfRange);
   1.994 +		return EFalse;
   1.995 +		}
   1.996 +
   1.997 +	// check if our buffer can hold requested data
   1.998 +#ifdef MSDC_MULTITHREADED
   1.999 +	if (iWriteDriveThread->iThreadContext->MaxBufferLength() < bLength)
  1.1000 +#else
  1.1001 +	TPtr8 writeBuf(NULL, 0);
  1.1002 +	iTransport->GetReadDataBufPtr(writeBuf);
  1.1003 +	if (writeBuf.MaxLength() < bLength)
  1.1004 +#endif
  1.1005 +		{
  1.1006 +		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
  1.1007 +		return EFalse;
  1.1008 +		}
  1.1009 +
  1.1010 +	if (!bytChk)
  1.1011 +		{
  1.1012 +		// BYTCHK==0 : Perform a medium verification with no data comparison and not transfer any data from the application client data-out buffer.
  1.1013 +		// The device should attempt to read from the specified locations
  1.1014 +#ifdef MSDC_MULTITHREADED
  1.1015 +		TPtr8 writeBuf = iWriteDriveThread->iThreadContext->GetReadBuffer(bLength);
  1.1016 +#else
  1.1017 +		writeBuf.SetLength(bLength);
  1.1018 +#endif
  1.1019 +		err = drive->Read(bOffset, bLength, writeBuf, drive->IsWholeMediaAccess());
  1.1020 +		if (err != KErrNone)
  1.1021 +			{
  1.1022 +			iSenseInfo.SetSense(TSenseInfo::EMisCompare);
  1.1023 +			return EFalse;
  1.1024 +			}
  1.1025 +		return ETrue;
  1.1026 +		}
  1.1027 +
  1.1028 +	// 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.
  1.1029 +	// 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.
  1.1030 +
  1.1031 +	iOffset = bOffset;
  1.1032 +	iLastCommand = EVerify10;
  1.1033 +	iLastLun = aLun;
  1.1034 +
  1.1035 +	iTransport->SetupReadData(bLength);
  1.1036 +
  1.1037 +	return ETrue;
  1.1038 +	}
  1.1039 +
  1.1040 +
  1.1041 +/**
  1.1042 +Called by the transport when the requested data has been read or an error has
  1.1043 +occurred during the read.
  1.1044 +
  1.1045 +@param aError Indicate if an error occurs during reading data by transport.
  1.1046 +@return KErrAbort if command processing is complete but has failed,
  1.1047 +        KErrCompletion if sufficient data is available in the buffer to process
  1.1048 +        the transfer immediately, KErrNotReady if insufficient data is
  1.1049 +        available in the buffer so the transport should wait for it to arrive,
  1.1050 +        KErrNone if command processing is complete and was successful.
  1.1051 +*/
  1.1052 +TInt CScsiProtocol::ReadComplete(TInt aError)
  1.1053 +	{
  1.1054 +	__FNLOG("CScsiProtocol::ReadComplete");
  1.1055 +	__PRINT1(_L("Error = 0x%X \n"), aError);
  1.1056 +	const TInt64 bOffset = iOffset;
  1.1057 +	TUint8 lastCommand = iLastCommand;
  1.1058 +	TUint lastLun = iLastLun;
  1.1059 +
  1.1060 +	iOffset = 0;
  1.1061 +	iLastCommand = EUndefinedCommand;
  1.1062 +	iLastLun = KUndefinedLun;
  1.1063 +
  1.1064 +	__PRINT1(_L("Last command was: %s\n"),
  1.1065 +			 (lastCommand == EUndefinedCommand) ? _S("Undefined") :
  1.1066 +			 ((lastCommand == EWrite10) ? _S("EWrite10") :
  1.1067 +			  ((lastCommand == EVerify10) ? _S("EVerify10") :
  1.1068 +			   _S("Unknown"))));
  1.1069 +
  1.1070 +	if (aError != KErrNone ||
  1.1071 +		lastCommand == EUndefinedCommand ||
  1.1072 +		lastLun == KUndefinedLun)
  1.1073 +		{
  1.1074 +		iSenseInfo.SetSense(TSenseInfo::EAbortedCommand);
  1.1075 +		return KErrAbort;
  1.1076 +		}
  1.1077 +
  1.1078 +	CMassStorageDrive* drive = GetCheckDrive(lastLun);
  1.1079 +	if (drive == NULL)
  1.1080 +		{
  1.1081 +		return KErrAbort;
  1.1082 +		}
  1.1083 +
  1.1084 +	if (lastCommand == EWrite10)
  1.1085 +		{
  1.1086 +		TPtrC8 writeBuf(NULL, 0);
  1.1087 +		iTransport->GetWriteDataBufPtr(writeBuf);
  1.1088 +		
  1.1089 +#ifdef USB_TRANSFER_PUBLISHER
  1.1090 +	iBytesWritten[lastLun] += writeBuf.Length();
  1.1091 +#endif
  1.1092 +
  1.1093 +#ifdef MSDC_MULTITHREADED
  1.1094 +		TInt err = iWriteDriveThread->WriteDriveData(drive, bOffset, writeBuf, ProcessWriteComplete, this);
  1.1095 +
  1.1096 +		if (err != KErrNone)
  1.1097 +			{
  1.1098 +			iDeferredSenseInfo.SetSense(TSenseInfo::EMediumError);
  1.1099 +			}
  1.1100 +
  1.1101 +		TUint thisLength = iWriteDriveThread->WriteBufferLength();
  1.1102 +#else
  1.1103 +#ifdef MEASURE_AND_DISPLAY_WRITE_TIME
  1.1104 +		RDebug::Print(_L("SCSI: writing %d bytes\n"), writeBuf.Length());
  1.1105 +		TTime t0, t1;
  1.1106 +		t0.HomeTime();
  1.1107 +#else
  1.1108 +		__PRINT1(_L("SCSI: writing %d bytes\n"), writeBuf.Length());
  1.1109 +#endif
  1.1110 +
  1.1111 +#ifdef INJECT_ERROR
  1.1112 +		if (writeBuf[0] == '2')
  1.1113 +		{
  1.1114 +			writeBuf[0] = 'x';
  1.1115 +			RDebug::Printf("Injecting error");
  1.1116 +		}
  1.1117 +
  1.1118 +		RDebug::Printf("%08lx %x [%x] [%x]", bOffset,writeBuf.Length(), 
  1.1119 +			writeBuf[0],
  1.1120 +			writeBuf[writeBuf.Length()-1]);
  1.1121 +#endif
  1.1122 +		
  1.1123 +		TInt err = drive->Write(bOffset, writeBuf, drive->IsWholeMediaAccess());
  1.1124 +
  1.1125 +#ifdef INJECT_ERROR
  1.1126 +		if (writeBuf[0] == 'x')
  1.1127 +		{
  1.1128 +			err = KErrUnknown;
  1.1129 +		}
  1.1130 +#endif
  1.1131 +
  1.1132 +#ifdef MEASURE_AND_DISPLAY_WRITE_TIME
  1.1133 +		t1.HomeTime();
  1.1134 +		const TTimeIntervalMicroSeconds time = t1.MicroSecondsFrom(t0);
  1.1135 +		const TUint time_ms = I64LOW(time.Int64() / 1000);
  1.1136 +		RDebug::Print(_L("SCSI: write took %d ms\n"), time_ms);
  1.1137 +#endif
  1.1138 +		if (err != KErrNone)
  1.1139 +			{
  1.1140 +			__PRINT1(_L("Error after write = 0x%X \n"), err);
  1.1141 +			iSenseInfo.SetSense(TSenseInfo::EAbortedCommand);
  1.1142 +			return KErrAbort;
  1.1143 +			}
  1.1144 +
  1.1145 +		TUint thisLength = writeBuf.Length();
  1.1146 +#endif // MSDC_MULTITHREADED
  1.1147 +		iOffset = bOffset + MAKE_TINT64(0, thisLength);
  1.1148 +		iBytesRemain -= thisLength;
  1.1149 +		if ((TInt)iBytesRemain > 0)
  1.1150 +			{
  1.1151 +			// More data is expected - set up another request to read from the host
  1.1152 +			iLastCommand = EWrite10;
  1.1153 +			iLastLun = lastLun;
  1.1154 +
  1.1155 +			TUint minLength = (iBytesRemain < iMediaWriteSize) ? iBytesRemain : iMediaWriteSize;
  1.1156 +			TUint bytesAvail = iTransport->BytesAvailable() & ~(KDefaultBlockSize-1);
  1.1157 +
  1.1158 +			TBool wait = EFalse;
  1.1159 +			thisLength = bytesAvail ? bytesAvail : minLength;
  1.1160 +			if (thisLength < minLength)
  1.1161 +				{
  1.1162 +				// Not enough data is available at the transport to satisfy the request,
  1.1163 +				// so return KErrNotReady to indicate that the transport should wait.
  1.1164 +				thisLength = minLength;
  1.1165 +				wait = ETrue;
  1.1166 +				}
  1.1167 +
  1.1168 +			thisLength = (thisLength > KMaxBufSize) ? KMaxBufSize : thisLength;
  1.1169 +
  1.1170 +			iTransport->SetupReadData(thisLength);
  1.1171 +
  1.1172 +			return wait ? KErrNotReady : KErrCompletion;
  1.1173 +			}
  1.1174 +		}
  1.1175 +	else if (lastCommand == EVerify10)
  1.1176 +		{
  1.1177 +		HBufC8* hostData = NULL;
  1.1178 +		TPtrC8 writeBuf(NULL, 0);
  1.1179 +		iTransport->GetWriteDataBufPtr(writeBuf);
  1.1180 +#ifdef MSDC_MULTITHREADED
  1.1181 +		TRAPD(err, hostData = HBufC8::NewL(writeBuf.Length()));
  1.1182 +#else
  1.1183 +		TRAPD(err, hostData = HBufC8::NewL(writeBuf.Length()));
  1.1184 +#endif
  1.1185 +		if (err != KErrNone || hostData == NULL)
  1.1186 +			{
  1.1187 +			iSenseInfo.SetSense(TSenseInfo::EAbortedCommand, TSenseInfo::EInsufficientRes);
  1.1188 +			return KErrAbort;
  1.1189 +			}
  1.1190 +
  1.1191 +#ifdef MSDC_MULTITHREADED
  1.1192 +		// copy the data
  1.1193 +		*hostData = writeBuf;
  1.1194 +		TPtr8 readBuf = iWriteDriveThread->iThreadContext->GetReadBuffer(); 
  1.1195 +		err = drive->Read(bOffset, writeBuf.Length(), readBuf, drive->IsWholeMediaAccess());
  1.1196 +		if (err == KErrNone)
  1.1197 +			{
  1.1198 +			err = (hostData->Compare(readBuf) == 0) ? KErrNone : KErrCorrupt;
  1.1199 +			}
  1.1200 +#else
  1.1201 +		*hostData = writeBuf;
  1.1202 +		TPtr8 readBuf((TUint8*) writeBuf.Ptr(), writeBuf.Length()); 
  1.1203 +		err = drive->Read(bOffset, writeBuf.Length(), readBuf, drive->IsWholeMediaAccess());
  1.1204 +		if (err == KErrNone)
  1.1205 +			{
  1.1206 +			err = (hostData->Compare(readBuf) == 0) ? KErrNone : KErrCorrupt;
  1.1207 +			}
  1.1208 +#endif
  1.1209 +
  1.1210 +		if (err != KErrNone)
  1.1211 +			{
  1.1212 +			iSenseInfo.SetSense(TSenseInfo::EMisCompare);
  1.1213 +			}
  1.1214 +
  1.1215 +		delete hostData;
  1.1216 +		}
  1.1217 +	else // unknown command
  1.1218 +		{
  1.1219 +		iSenseInfo.SetSense(TSenseInfo::EAbortedCommand);
  1.1220 +		}
  1.1221 +	return iSenseInfo.SenseOk() ? KErrNone : KErrAbort;
  1.1222 +	}
  1.1223 +
  1.1224 +
  1.1225 +/**
  1.1226 +Command Parser for the MODE SENSE(06) command (0x1A)
  1.1227 +
  1.1228 +@return ETrue if successful.
  1.1229 +*/
  1.1230 +TBool CScsiProtocol::HandleModeSense(TPtrC8& aData, TUint aLun)
  1.1231 +	{
  1.1232 +	__FNLOG("CScsiProtocol::HandleModeSense");
  1.1233 +
  1.1234 +	TInt pageCode = aData[3] & 0x3F;
  1.1235 +	TUint8 pageControl= static_cast<TUint8>(aData[3] >>6);
  1.1236 +
  1.1237 +	// reserve 4 bytes for Length, Media type, Device-specific parameter and Block descriptor length
  1.1238 +
  1.1239 +	if (pageCode != KAllPages || pageControl == KChangeableValues) 
  1.1240 +		{
  1.1241 +		__PRINT(_L("TSenseInfo::EIllegalRequest,TSenseInfo::EInvalidFieldInCdb"));
  1.1242 +		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest,TSenseInfo::EInvalidFieldInCdb);
  1.1243 +		return EFalse;
  1.1244 +		}
  1.1245 +
  1.1246 +	TPtr8 writeBuf(NULL, 0);
  1.1247 +	iTransport->GetCommandBufPtr(writeBuf, KModeSenseCommandLength);
  1.1248 +	writeBuf.FillZ(KModeSenseCommandLength);
  1.1249 +
  1.1250 +	if (pageControl != KDefaultValues)
  1.1251 +		{
  1.1252 +		//check if drive write protected
  1.1253 +		CMassStorageDrive* drive=GetCheckDrive(aLun);
  1.1254 +		if (drive == NULL)
  1.1255 +			{
  1.1256 +			__PRINT(_L("drive == null"));
  1.1257 +			return EFalse;
  1.1258 +			}
  1.1259 +
  1.1260 +		TLocalDriveCapsV4 driveInfo;
  1.1261 +		TInt err = drive->Caps(driveInfo);
  1.1262 +		if (err != KErrNone)
  1.1263 +			{
  1.1264 +			__PRINT(_L("TSenseInfo::ENotReady"));
  1.1265 +			iSenseInfo.SetSense(TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent);
  1.1266 +			return EFalse ;
  1.1267 +			}
  1.1268 +
  1.1269 +		if (driveInfo.iMediaAtt & KMediaAttWriteProtected)
  1.1270 +			{
  1.1271 +			writeBuf[2] = 1<<7;  // set SWP bit at the Device Specific parameters
  1.1272 +			}
  1.1273 +		}
  1.1274 +
  1.1275 +	writeBuf[0]=3;  //Sending only Mode parameter header
  1.1276 +
  1.1277 +	TPtrC8 writeBuf1 = writeBuf;
  1.1278 +
  1.1279 +	iTransport->SetupWriteData(writeBuf1);
  1.1280 +
  1.1281 +	return (iSenseInfo.SenseOk());
  1.1282 +	}
  1.1283 +
  1.1284 +