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