os/kernelhwsrv/kerneltest/f32test/shostmassstorage/testclient/usbtestmsclient/protocol/cscsiserverprotocol.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of the License "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 //
    15 
    16 #include <e32base.h>
    17 #include <f32file.h>
    18 #include <e32property.h>
    19 
    20 #include "mstypes.h"
    21 #include "msctypes.h"
    22 #include "usbmsshared.h"
    23 
    24 #include "drivemanager.h"
    25 #include "drivepublisher.h"
    26 #include "tscsiserverreq.h"
    27 #include "tscsiservercmds.h"
    28 #include "mserverprotocol.h"
    29 #include "mdevicetransport.h"
    30 
    31 #include "testman.h"
    32 #include "cscsiserverprotocol.h"
    33 #include "debug.h"
    34 #include "msdebug.h"
    35 
    36 
    37 TMediaWriteMan::TMediaWriteMan()
    38 :   iActive(EFalse),
    39     iOffset(0),
    40 	iMediaWriteSize(KDefaultMediaWriteSize)
    41     {
    42     }
    43 
    44 void TMediaWriteMan::ReportHighSpeedDevice()
    45 	{
    46     __MSFNLOG
    47 	iMediaWriteSize = KHsMediaWriteSize;
    48 	__PRINT1(_L("HS Device reported: SCSI will use %d bytes disk write size"), iMediaWriteSize);
    49 	}
    50 
    51 
    52 TInt64 TMediaWriteMan::Start(TUint32 aLba, TUint32 aLength, TUint32 aBlockSize)
    53     {
    54     iActive = ETrue;
    55     iOffset = static_cast<TInt64>(aLba) * aBlockSize;
    56     iBytesRemain = aLength * aBlockSize;
    57 
    58 	TInt64 theEnd = iOffset + iBytesRemain;
    59     return theEnd;
    60     }
    61 
    62 TUint32 TMediaWriteMan::NextPacket()
    63     {
    64     iActive = ETrue;
    65     return (iBytesRemain < iMediaWriteSize) ? iBytesRemain : iMediaWriteSize;
    66     }
    67 
    68 
    69 void TMediaWriteMan::Reset()
    70     {
    71     iActive = EFalse;
    72     iOffset = 0;
    73     }
    74 
    75 void TMediaWriteMan::SetOffset(const TInt64& aOffset, TUint aLength)
    76     {
    77     iOffset = aOffset + aLength;
    78     iBytesRemain -= aLength;
    79     }
    80 
    81 TUint32 TMediaWriteMan::GetPacketLength() const
    82     {
    83     // KMaxBufSize or the MediaWriteSize, whichever is smallest.
    84 	TUint32 thisLength = (iBytesRemain > KMaxBufSize) ? KMaxBufSize : iBytesRemain;
    85 	thisLength = (thisLength > iMediaWriteSize) ? iMediaWriteSize : thisLength;
    86     return thisLength;
    87     }
    88 
    89 
    90 /**
    91 Creates the CScsiProtocol object.  Called during controller initialisation.
    92 
    93 @param aDriveManager reference to the drive manager object
    94 */
    95 CScsiServerProtocol* CScsiServerProtocol::NewL(CDriveManager& aDriveManager)
    96 	{
    97     __MSFNSLOG
    98 	CScsiServerProtocol* self = new (ELeave) CScsiServerProtocol(aDriveManager);
    99 	CleanupStack::PushL(self);
   100 	self->ConstructL();
   101 	CleanupStack::Pop();
   102 	return self;
   103 	}
   104 
   105 #ifdef MSDC_TESTMODE
   106 CScsiServerProtocol* CScsiServerProtocol::NewL(CDriveManager& aDriveManager, TTestParser* aTestParser)
   107 	{
   108     __MSFNSLOG
   109 	CScsiServerProtocol* self = new (ELeave) CScsiServerProtocol(aDriveManager, aTestParser);
   110 	CleanupStack::PushL(self);
   111 	self->ConstructL();
   112 	CleanupStack::Pop();
   113 	return self;
   114 	}
   115 #endif
   116 
   117 
   118 /**
   119 c'tor
   120 
   121 @param aDriveManager reference to the drive manager object
   122 */
   123 CScsiServerProtocol::CScsiServerProtocol(CDriveManager& aDriveManager)
   124 :   iDriveManager(aDriveManager)
   125 	{
   126     __MSFNLOG
   127 
   128 	iWriteTransferPublisher = CUsbWriteTransferPublisher::NewL(iBytesWritten);
   129 	iReadTransferPublisher = CUsbReadTransferPublisher::NewL(iBytesRead);
   130 
   131 	for (TUint i = 0; i < KUsbMsMaxDrives; i++)
   132 		{
   133 		iBytesRead[i] = 0;
   134 		iBytesWritten[i] = 0;
   135 		}
   136 	}
   137 
   138 #ifdef MSDC_TESTMODE
   139 CScsiServerProtocol::CScsiServerProtocol(CDriveManager& aDriveManager, TTestParser* aTestParser)
   140 :   iDriveManager(aDriveManager),
   141     iTestParser(aTestParser)
   142 	{
   143     __MSFNLOG
   144 
   145 	iWriteTransferPublisher = CUsbWriteTransferPublisher::NewL(iBytesWritten);
   146 	iReadTransferPublisher = CUsbReadTransferPublisher::NewL(iBytesRead);
   147 
   148 	for (TUint i = 0; i < KUsbMsMaxDrives; i++)
   149 		{
   150 		iBytesRead[i] = 0;
   151 		iBytesWritten[i] = 0;
   152 		}
   153 	}
   154 #endif
   155 
   156 
   157 CScsiServerProtocol::~CScsiServerProtocol()
   158 	{
   159     __MSFNLOG
   160     iDataBuf.Close();
   161 	delete iWriteTransferPublisher;
   162 	delete iReadTransferPublisher;
   163 	}
   164 
   165 
   166 void CScsiServerProtocol::ConstructL()
   167 	{
   168     __MSFNLOG
   169 	}
   170 
   171 
   172 /**
   173 Associates the transport with the protocol. Called during initialisation of the controller.
   174 
   175 @param aTransport pointer to the transport object
   176 */
   177 void CScsiServerProtocol::RegisterTransport(MDeviceTransport* aTransport)
   178 	{
   179     __MSFNLOG
   180 	iTransport = aTransport;
   181 	}
   182 
   183 
   184 /**
   185 Called by the Transport when it detects that the USB device is either running
   186 at High Speed or is at least capable of HS operation. The Protocol can use this
   187 information (for instance) to select the optimal write block size to use.
   188 
   189 This function is preferably called before actual MS data transfer operation
   190 starts, and usually only once.
   191 
   192 */
   193 void CScsiServerProtocol::ReportHighSpeedDevice()
   194 	{
   195     __MSFNLOG
   196     iMediaWriteMan.ReportHighSpeedDevice();
   197 	}
   198 
   199 
   200 void CScsiServerProtocol::SetParameters(const TMassStorageConfig& aConfig)
   201 	{
   202     __MSFNLOG
   203 	iConfig = aConfig;
   204 	}
   205 
   206 
   207 /**
   208 Called by the transport layer when a packet is available for decoding.
   209 If an error occurs, the sense code is updated and EFalse is returned.
   210 
   211 @param aData
   212 
   213 @return  ETrue if command was decoded and executed successfully
   214 */
   215 TBool CScsiServerProtocol::DecodePacket(TPtrC8& aData, TUint8 aLun)
   216 	{
   217     __MSFNLOG
   218     TScsiServerReq* cdb = NULL;
   219     TRAPD(err, cdb = cdb->CreateL(static_cast<TScsiServerReq::TOperationCode>(aData[0]), aData));
   220 
   221     TBool decodeGood = EFalse;
   222     if (err == KErrNotSupported)
   223     	iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidCmdCode);
   224 	else if (err != KErrNone)
   225 		iSenseInfo.SetSense(TSenseInfo::EAbortedCommand, TSenseInfo::EInsufficientRes);
   226     else if (cdb->iNaca) // Check the CONTROL byte
   227 		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
   228     else if (cdb->iLink)
   229         iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
   230     else
   231         {
   232         TScsiServerReq::TOperationCode operationCode = cdb->iOperationCode;
   233         if (aLun > iDriveManager.MaxLun())
   234             {
   235             __PRINT(_L("No drive available\n"));
   236             iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::ELuNotSupported);
   237             }
   238         else
   239             {
   240             iLun = aLun;
   241             if (operationCode != TScsiServerReq::ERequestSense)
   242                 {
   243                 iSenseInfo.SetSense(TSenseInfo::ENoSense);
   244                 }
   245 
   246             switch (operationCode)
   247                 {
   248             case TScsiServerReq::ETestUnitReady:
   249                 HandleUnitReady();
   250                 break;
   251 
   252             case TScsiServerReq::ERequestSense:
   253                 HandleRequestSense(*cdb);
   254                 break;
   255 
   256             case TScsiServerReq::EInquiry:
   257                 HandleInquiry(*cdb);
   258                 break;
   259 
   260             case TScsiServerReq::EModeSense6:
   261                 HandleModeSense6(*cdb);
   262                 break;
   263 
   264             case TScsiServerReq::EStartStopUnit:
   265                 HandleStartStopUnit(*cdb);
   266                 break;
   267 
   268             case TScsiServerReq::EPreventMediaRemoval:
   269                 HandlePreventMediaRemoval(*cdb);
   270                 break;
   271 
   272             case TScsiServerReq::EReadCapacity10:
   273                 HandleReadCapacity10(*cdb);
   274                 break;
   275 
   276             case TScsiServerReq::ERead10:
   277                 HandleRead10(*cdb);
   278                 break;
   279 
   280             case TScsiServerReq::EWrite10:
   281                 HandleWrite10(*cdb);
   282                 break;
   283 
   284             case TScsiServerReq::EReadFormatCapacities:
   285                 HandleReadFormatCapacities(*cdb);
   286                 break;
   287 
   288             default:
   289                 iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidCmdCode);
   290                 break;
   291                 }
   292             }
   293         __PRINT1(_L("DecodePacket result = %d"), iSenseInfo.SenseOk());
   294     	decodeGood = iSenseInfo.SenseOk();
   295         }
   296 
   297     delete cdb;
   298     return decodeGood;
   299 	}
   300 
   301 
   302 /**
   303 Checks if drive ready
   304 
   305 @param aLun Logic unit number
   306 @return pointer to drive correspondent to LUN if drive mounted and ready, NULL otherwise
   307 */
   308 CMassStorageDrive* CScsiServerProtocol::GetCheckDrive()
   309 	{
   310     __MSFNLOG
   311 #ifdef MSDC_TESTMODE
   312     if (iTestParser && iTestParser->SenseError() != TTestParser::ETestSenseErrorNoSense)
   313         {
   314         switch (iTestParser->SenseError())
   315             {
   316             case TTestParser::ETestSenseErrorMediaNotPresent:
   317                 __TESTMODEPRINT("Set SENSE ERROR(ENotReady, EMediaNotPresent)");
   318                 iSenseInfo.SetSense(TSenseInfo::ENotReady,
   319                                     TSenseInfo::EMediaNotPresent);
   320                 break;
   321 
   322 
   323             case TTestParser::ETestSenseErrorUnitAttention:
   324             default:
   325                 __TESTMODEPRINT("Set SENSE ERROR(EUnitAttention, ENotReadyToReadyChange)");
   326                 iSenseInfo.SetSense(TSenseInfo::EUnitAttention,
   327                                     TSenseInfo::ENotReadyToReadyChange);
   328                 break;
   329             }
   330         iTestParser->ClrSenseError();
   331         return NULL;
   332         }
   333 #endif
   334 
   335 	CMassStorageDrive* drive = iDriveManager.Drive(iLun);
   336 	CMassStorageDrive::TMountState mountState = drive->MountState();
   337 
   338 	if (mountState == CMassStorageDrive::EDisconnected || mountState == CMassStorageDrive::EConnecting)
   339 		{
   340 		__PRINT(_L("Drive disconnected\n"));
   341 		iSenseInfo.SetSense(TSenseInfo::ENotReady,
   342 							TSenseInfo::EMediaNotPresent);
   343 		return NULL;
   344 		}
   345 
   346 	TLocalDriveRef::TDriveState state = drive->CheckDriveState();
   347 	if (state == TLocalDriveRef::EMediaNotPresent || state == TLocalDriveRef::ELocked)
   348 		{
   349 		__PRINT1(_L("Media not present or locked. (state =0x%X)\n"),state);
   350 		iSenseInfo.SetSense(TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent);
   351 		return NULL;
   352 		}
   353 
   354 	if (drive->IsMediaChanged(ETrue))  //reset "media changed" status
   355 		{
   356 		__PRINT(_L("Media was changed\n"));
   357 		// SAM-2 Section 5.9.5 Unit Attention Condition
   358 		iSenseInfo.SetSense(TSenseInfo::EUnitAttention, TSenseInfo::ENotReadyToReadyChange);
   359 		iDriveManager.Connect(iLun);   //publish event to USB app
   360 		return NULL;
   361 		}
   362 
   363 	if (mountState == CMassStorageDrive::EDisconnecting)
   364 		{
   365 		__PRINT(_L("Drive disconnecting\n"));
   366 		iSenseInfo.SetSense(TSenseInfo::ENotReady,
   367 							TSenseInfo::EMediaNotPresent);
   368 		return NULL;
   369 		}
   370 
   371 	return drive;
   372 	}
   373 
   374 
   375 /**
   376 Command Parser for the UNIT READY command (0x00)
   377 
   378 @param aLun Logic unit number
   379 @return ETrue if successful,
   380 */
   381 TBool CScsiServerProtocol::HandleUnitReady()
   382 	{
   383     __MSFNLOG
   384 	return GetCheckDrive() ? ETrue : EFalse;
   385 	}
   386 
   387 
   388 /**
   389 Command Parser for the REQUEST SENSE command (0x03)
   390 
   391 @return ETrue if successful,
   392 */
   393 TBool CScsiServerProtocol::HandleRequestSense(const TScsiServerReq& aRequest)
   394 	{
   395     __MSFNLOG
   396     const TScsiServerRequestSenseReq request = static_cast<const TScsiServerRequestSenseReq&>(aRequest);
   397 	__PRINT1(_L("length = %d\n"), request.iAllocationLength);
   398 
   399     TScsiServerRequestSenseResp requestSense;
   400     requestSense.iAllocationLength = request.iAllocationLength;
   401 
   402     requestSense.SetResponseCode(TScsiServerRequestSenseResp::ECurrentErrors);
   403     requestSense.iSensePtr = &iSenseInfo;
   404     requestSense.Encode(iCommandBuf);
   405 
   406 	__PRINT4(_L("Response=0x%x Sense=0x%x, Additional=0x%x, Qualifier=0x%x\n"),
   407 				iCommandBuf[0], iCommandBuf[02], iCommandBuf[12], iCommandBuf[13]);
   408 
   409 	TPtrC8 writeBuf = iCommandBuf.Left(request.iAllocationLength);
   410 	iTransport->SetupDataIn(writeBuf);
   411 
   412 	// clear the sense info
   413 	iSenseInfo.SetSense(TSenseInfo::ENoSense);
   414 	return ETrue;
   415 	}
   416 
   417 
   418 /**
   419 Command Parser for the INQUIRY command (0x12)
   420 
   421 @param aLun Logic unit number
   422 @return ETrue if successful,
   423 */
   424 TBool CScsiServerProtocol::HandleInquiry(const TScsiServerReq& aRequest)
   425 	{
   426     __MSFNLOG
   427     const TScsiServerInquiryReq request = static_cast<const TScsiServerInquiryReq&>(aRequest);
   428 
   429 	if (request.iCmdDt || request.iEvpd || request.iPage || iLun >= KUsbMsMaxDrives)
   430 		{
   431 		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
   432 		return EFalse;
   433 		}
   434 
   435     TScsiServerInquiryResp inquiry(iConfig);
   436 
   437     inquiry.SetAllocationLength(request.iAllocationLength);
   438 
   439 #ifdef MSDC_TESTMODE
   440     if (iTestParser && !iTestParser->Removable())
   441         {
   442         __TESTMODEPRINT("RMB Cleared");
   443         inquiry.SetNotRemovable();
   444         }
   445 #endif
   446 
   447     inquiry.Encode(iCommandBuf);
   448 
   449     TUint length = inquiry.Length();
   450 
   451 	TPtrC8 writeBuf = iCommandBuf.Left(length);
   452 	iTransport->SetupDataIn(writeBuf);
   453 
   454 	iSenseInfo.SetSense(TSenseInfo::ENoSense);
   455 	return ETrue;
   456 	}
   457 
   458 
   459 /**
   460  Command Parser for the START STOP UNIT command (0x1B)
   461 
   462  @param aData command data (started form position 1)
   463  @param aLun Logic unit number
   464  @return ETrue if successful, TFalse otherwise
   465  */
   466 TBool CScsiServerProtocol::HandleStartStopUnit(const TScsiServerReq& aRequest)
   467 	{
   468     __MSFNLOG
   469 
   470 	const TScsiServerStartStopUnitReq request = static_cast<const TScsiServerStartStopUnitReq&>(aRequest);
   471 
   472 	if (request.iLoej)
   473 		{
   474 		if(request.iStart)	//Start unit
   475 			{
   476 			iDriveManager.Connect(iLun);
   477 			__PRINT(_L("Load media\n"));
   478 
   479             // rd/wr publisher
   480 			iBytesRead[iLun] = 0;
   481 			iBytesWritten[iLun] = 0;
   482 
   483 			// publish the initial values
   484 			iWriteTransferPublisher->DoPublishDataTransferredEvent();
   485 			iReadTransferPublisher->DoPublishDataTransferredEvent();
   486 			}
   487 		else		//Stop unit
   488 			{
   489 			iDriveManager.SetCritical(iLun, EFalse);
   490 			iDriveManager.Disconnect(iLun);
   491 			__PRINT(_L("Unload media\n"));
   492 			}
   493 		}
   494 
   495 	if (request.iImmed)
   496 		{
   497 		return ETrue;
   498 		}
   499 
   500 	CMassStorageDrive* drive = iDriveManager.Drive(iLun);
   501 
   502 	TInt  timeLeft (20);   // 1 sec timeout
   503 	CMassStorageDrive::TMountState mountState;
   504 
   505 	do
   506 		{
   507 		User::After(1000 * 50);		// 50 mSec
   508 		--timeLeft;
   509 		mountState = drive->MountState();
   510 
   511 		if ((!request.iStart && mountState != CMassStorageDrive::EConnected)
   512 			 ||
   513 			 (request.iStart &&
   514 				(mountState == CMassStorageDrive::EDisconnecting ||
   515                mountState == CMassStorageDrive::EConnected)))
   516 			{
   517 			return ETrue;
   518 			}
   519 		} while (timeLeft>0);
   520 
   521 	//timeout happend
   522 	iSenseInfo.SetSense(TSenseInfo::ENotReady,
   523 						TSenseInfo::EAscLogicalUnitDoesNotRespondToSelection);
   524 	return EFalse;
   525 	}
   526 
   527 
   528 /**
   529 Command Parser for the PREVENT/ALLOW MEDIA REMOVAL command (0x1E)
   530 
   531 @param aData command data (started form position 1)
   532 @param aLun Logic unit number
   533 @return ETrue if successful.
   534 */
   535 TBool CScsiServerProtocol::HandlePreventMediaRemoval(const TScsiServerReq& aRequest)
   536 	{
   537     __MSFNLOG
   538 	const TScsiServerPreventMediaRemovalReq& request = static_cast<const TScsiServerPreventMediaRemovalReq&>(aRequest);
   539 	__FNLOG("CScsiProtocol::HandlePreventMediaRemoval");
   540 	CMassStorageDrive* drive = GetCheckDrive();
   541 
   542 	if (drive == NULL)
   543 		{
   544 		return EFalse;
   545 		}
   546 	iDriveManager.SetCritical(iLun, request.iPrevent);
   547 	return ETrue;
   548 	}
   549 
   550 
   551 /** Cancel active state, Invoked by transnport when it stops */
   552 TInt CScsiServerProtocol::Cancel()
   553 	{
   554     __MSFNLOG
   555 	iDriveManager.SetCritical(CDriveManager::KAllLuns, EFalse);
   556 	return KErrNone;
   557 	}
   558 
   559 
   560 TBool CScsiServerProtocol::HandleReadFormatCapacities(const TScsiServerReq& aRequest)
   561 /**
   562  * Command Parser for the READ FORMAT CAPACITIES command (0x23)
   563  *
   564  * @return ETrue if successful, else a standard Symbian OS error code.
   565  */
   566 	{
   567     __MSFNLOG
   568 	const TScsiServerReadFormatCapacitiesReq& request = static_cast<const TScsiServerReadFormatCapacitiesReq&>(aRequest);
   569 
   570     CMassStorageDrive* drive = NULL;
   571     for (TInt i = 0; i < 10; i++)
   572         {
   573         drive = GetCheckDrive();
   574         if (drive)
   575             {
   576             break;
   577             }
   578         User::After(100000);
   579         }
   580 
   581 	if (!drive)
   582 		{
   583         return EFalse;
   584 		}
   585 
   586 	TUint32 numBlocks = I64LOW(drive->MediaParams().NumBlocks());
   587 
   588     TScsiServerReadFormatCapacitiesResp response(request.AllocationLength());
   589     response.SetNumberBlocks(numBlocks);
   590 
   591     response.Encode(iCommandBuf);
   592 	TPtrC8 writeBuf = iCommandBuf;
   593 	iTransport->SetupDataIn(writeBuf);
   594 	return ETrue;
   595 	}
   596 
   597 
   598 /**
   599 Command Parser for the READ CAPACITY(10) command (0x25)
   600 
   601 @param aData command data (started form position 1)
   602 @param aLun Logic unit number
   603 @return ETrue if successful.
   604 */
   605 TBool CScsiServerProtocol::HandleReadCapacity10(const TScsiServerReq& aRequest)
   606 	{
   607     __MSFNLOG
   608 	const TScsiServerReadCapacity10Req& request = static_cast<const TScsiServerReadCapacity10Req&>(aRequest);
   609 	CMassStorageDrive* drive = GetCheckDrive();
   610 	if (drive == NULL)
   611 		{
   612 		return EFalse;
   613 		}
   614 
   615 	if (request.iPmi || request.iLogicalBlockAddress)   //do not support partial medium indicator
   616 		{
   617 		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
   618 		return EFalse;
   619 		}
   620 
   621     TScsiServerReadCapacity10Resp response;
   622     response.Set(drive->MediaParams().BlockSize(), drive->MediaParams().NumBlocks());
   623     response.Encode(iCommandBuf);
   624 
   625 	TPtrC8 writeBuf = iCommandBuf;
   626 	iTransport->SetupDataIn(writeBuf);
   627 
   628 	return KErrNone;
   629 	}
   630 
   631 
   632 /**
   633 Command Parser for the READ10 command (0x28)
   634 
   635 @param aData command data (started form position 1)
   636 @param aLun Logic unit number
   637 @return ETrue if successful.
   638 */
   639 TBool CScsiServerProtocol::HandleRead10(const TScsiServerReq& aRequest)
   640 	{
   641     __MSFNLOG
   642 	const TScsiServerRead10Req& request = static_cast<const TScsiServerRead10Req&>(aRequest);
   643 	CMassStorageDrive* drive = GetCheckDrive();
   644 	if (drive == NULL)
   645 		{
   646 		return EFalse;
   647 		}
   648 
   649 	if (request.iProtect)
   650 		{
   651 		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
   652 		return EFalse;
   653 		}
   654 
   655 	if (!request.iTransferLength)
   656 		{
   657 		return ETrue; // do nothing - this is not an error
   658 		}
   659 
   660     TUint32 blockSize = drive->MediaParams().BlockSize();
   661 
   662 	const TInt64 bOffset = static_cast<TInt64>(request.iLogicalBlockAddress) * blockSize;
   663 	const TInt bLength = request.iTransferLength * blockSize;
   664 	const TInt64 theEnd = bOffset + bLength;
   665 
   666 	if (theEnd > drive->MediaParams().Size())  //check if media big enough for this request
   667 		{
   668 		__PRINT(_L("err - Request ends out of media\n"));
   669 		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::ELbaOutOfRange);
   670 		return EFalse;
   671 		}
   672 
   673 	// check if our buffer can hold requested data
   674 	if (iDataBuf.MaxLength() < bLength)
   675 		{
   676         TRAPD(err,iDataBuf.ReAllocL(bLength));
   677         if (err)
   678             {
   679             __PRINT(_L("err - Buffer too small\n"));
   680             iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
   681             return EFalse;
   682             }
   683 		}
   684 
   685     iDataBuf.SetLength(bLength);
   686 	TInt err = drive->Read(bOffset, bLength, iDataBuf);
   687 	if (err != KErrNone)
   688 		{
   689 		__PRINT1(_L("Read failed, err=%d\n"), err);
   690 		iSenseInfo.SetSense(TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent);
   691 		return EFalse;
   692 		}
   693 
   694 	TPtrC8 writeBuf = iDataBuf;
   695 
   696     // rd publisher
   697 	iBytesRead[iLun] += writeBuf.Length();
   698 	iReadTransferPublisher->StartTimer();
   699 
   700 	// Set up data write to the host
   701 #ifdef MSDC_TESTMODE
   702     if (iTestParser)
   703         {
   704         TBool test = iTestParser->DInSearch(writeBuf);
   705         }
   706 #endif
   707 	iTransport->SetupDataIn(writeBuf);
   708 	return ETrue;
   709 	}
   710 
   711 
   712 /**
   713 Command Parser for the WRITE(10) command (0x2A)
   714 
   715 @param aData command data (started form position 1)
   716 @param aLun Logic unit number
   717 @return ETrue if successful.
   718 */
   719 TBool CScsiServerProtocol::HandleWrite10(const TScsiServerReq& aRequest)
   720 	{
   721     __MSFNLOG
   722 	const TScsiServerWrite10Req& request = static_cast<const TScsiServerWrite10Req&>(aRequest);
   723 	CMassStorageDrive* drive = GetCheckDrive();
   724 	if (drive == NULL)
   725 		{
   726 		return EFalse;
   727 		}
   728 	if (request.iProtect)
   729 		{
   730 		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
   731 		return EFalse;
   732 		}
   733 
   734 	if (!request.iTransferLength)
   735 		{
   736 		return ETrue; // do nothing - this is not an error
   737 		}
   738 
   739     const TMediaParams& params = drive->MediaParams();
   740 
   741 	if (params.IsWriteProtected() ||
   742 		params.IsLocked())
   743 		{
   744 		iSenseInfo.SetSense(TSenseInfo::EDataProtection, TSenseInfo::EWriteProtected);
   745 		return EFalse;
   746 		}
   747 
   748     TInt64 theEnd = iMediaWriteMan.Start(request.iLogicalBlockAddress, request.iTransferLength, params.BlockSize());
   749 	if (theEnd > params.Size())  //check if media big enough for this request
   750 		{
   751 		__PRINT(_L("err - Request ends out of media\n"));
   752 		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::ELbaOutOfRange);
   753 		return EFalse;
   754 		}
   755 
   756     TUint32 thisLength = iMediaWriteMan.GetPacketLength();
   757 
   758     // check if our buffer can hold requested data
   759     if (iDataBuf.MaxLength() < thisLength)
   760         {
   761         TRAPD(err,iDataBuf.ReAllocL(thisLength));
   762         if (err)
   763             {
   764             __PRINT(_L("err - Buffer too small\n"));
   765             iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
   766             return EFalse;
   767             }
   768         }
   769 
   770 	iDataBuf.SetLength(thisLength);
   771 	TPtr8 readBuf = iDataBuf.LeftTPtr(iDataBuf.Length());
   772 
   773     // wr publisher
   774 	iBytesWritten[iLun] += readBuf.Length();
   775 	iWriteTransferPublisher->StartTimer();
   776 	iTransport->SetupDataOut(readBuf);
   777 	return ETrue;
   778 	}
   779 
   780 
   781 void CScsiServerProtocol::MediaWriteAbort()
   782     {
   783     __MSFNLOG
   784     iMediaWriteMan.Reset();
   785     iSenseInfo.SetSense(TSenseInfo::EAbortedCommand);
   786     }
   787 
   788 /**
   789 Called by the transport when the requested data has been read or an error has
   790 occurred during the read.
   791 
   792 @param aError Indicate if an error occurs during reading data by transport.
   793 @return KErrAbort if command processing is complete but has failed,
   794         KErrCompletion if sufficient data is available in the buffer to process
   795         the transfer immediately, KErrNotReady if insufficient data is
   796         available in the buffer so the transport should wait for it to arrive,
   797         KErrNone if command processing is complete and was successful.
   798 */
   799 TInt CScsiServerProtocol::MediaWritePacket(TUint& aBytesWritten)
   800 	{
   801     __MSFNLOG
   802     aBytesWritten = 0;
   803     if (iMediaWriteMan.Active() == EFalse)
   804         {
   805         iSenseInfo.SetSense(TSenseInfo::EAbortedCommand);
   806         return KErrAbort;
   807         }
   808 
   809     CMassStorageDrive* drive = GetCheckDrive();
   810     if (drive == NULL)
   811         {
   812         return KErrAbort;
   813         }
   814 
   815 #ifdef MSDC_TESTMODE
   816     if (iTestParser && iTestParser->Enabled())
   817         {
   818         TInt testCase = iTestParser->TestCase();
   819         if (testCase == TTestParser::ETestCaseDoStallData)
   820             {
   821             iTestParser->DecTestCounter();
   822 
   823             TInt testCounter = iTestParser->TestCounter();
   824             if (testCounter == 1)
   825                 {
   826                 __TESTMODEPRINT1("Aborting MediaWritePacket (Data Stall) x%x", iMediaWriteMan.BytesRemain());
   827                 __TESTMODEPRINT2("Offset=0x%lx Length=%x",
   828                                  iMediaWriteMan.Offset(), iDataBuf.Length());
   829                 return KErrNone;
   830                 }
   831             else if (testCounter == 0)
   832                 {
   833                 // Display the next write and clear the test
   834                 iTestParser->ClrTestCase();
   835                 __TESTMODEPRINT2("Offset=0x%lx Length=%x",
   836                                  iMediaWriteMan.Offset(), iDataBuf.Length());
   837                 }
   838             }
   839         else if (testCase == TTestParser::ETestCaseDoResidue)
   840             {
   841             iTestParser->DecTestCounter();
   842             TInt testCounter = iTestParser->TestCounter();
   843 
   844             if (testCounter == 1)
   845                 {
   846                 // abort write and leave residue
   847                 __TESTMODEPRINT1("Aborting MediaWritePacket (Data Residue) x%x", iMediaWriteMan.BytesRemain());
   848                 __TESTMODEPRINT2("Offset=0x%lx Length=0x%x",
   849                                  iMediaWriteMan.Offset(), iDataBuf.Length());
   850                 aBytesWritten = 0;
   851                 return KErrAbort;
   852                 }
   853             else if (testCounter == 0)
   854                 {
   855                 // Display the next write and clear the test
   856                 iTestParser->ClrTestCase();
   857                 __TESTMODEPRINT2("MediaWritePacket Offset=0x%lx Length=0x%x",
   858                                  iMediaWriteMan.Offset(), iDataBuf.Length());
   859                 }
   860             else
   861                 {
   862                 __TESTMODEPRINT3("MediaWritePacket[%x] Offset=0x%lx Length=0x%x",
   863                                  testCounter, iMediaWriteMan.Offset(), iDataBuf.Length());
   864                 }
   865 
   866             }
   867         }
   868 #endif
   869 
   870 	const TInt64 bOffset = iMediaWriteMan.Offset();
   871     iMediaWriteMan.Reset();
   872 
   873    	__PRINT1(_L("SCSI: writing %d bytes\n"), iDataBuf.Length());
   874 
   875     TInt err = KErrNone;
   876 #ifdef MSDC_TESTMODE
   877     if (iTestParser)
   878         {
   879         TBool test = iTestParser->DoutSearch(iDataBuf);
   880         if (test)
   881             {
   882             // Do not write test control blocks to media
   883             }
   884         else
   885             {
   886             // ********* Write data to the drive ********
   887             err = drive->Write(bOffset, iDataBuf);
   888             }
   889         }
   890 #else
   891     // ********* Write data to the drive ********
   892    	err = drive->Write(bOffset, iDataBuf);
   893 #endif
   894    	if (err != KErrNone)
   895    		{
   896    		__PRINT1(_L("Error after write = 0x%X \n"), err);
   897    		iSenseInfo.SetSense(TSenseInfo::EAbortedCommand);
   898    		return KErrAbort;
   899    		}
   900 
   901    	TUint thisLength = iDataBuf.Length();
   902     aBytesWritten = thisLength;
   903 
   904     iMediaWriteMan.SetOffset(bOffset, thisLength);
   905 
   906    	if (iMediaWriteMan.BytesRemain() == 0)
   907         {
   908         return iSenseInfo.SenseOk() ? KErrNone : KErrAbort;
   909         }
   910 
   911     // More data is expected - set up another request to read from the host
   912     const TUint32 nextPacketLength = iMediaWriteMan.NextPacket();
   913  	TUint bytesAvail = iTransport->BytesAvailable() & ~(drive->MediaParams().BlockSize()-1);
   914 
   915  	TBool wait = EFalse;
   916 
   917     thisLength = nextPacketLength;
   918     if (bytesAvail)
   919         {
   920         if (bytesAvail < nextPacketLength)
   921             {
   922             // Not enough data is available at the transport to satisfy the
   923             // request, so return KErrNotReady to indicate that the transport
   924             // should wait.
   925             thisLength = nextPacketLength;
   926             wait = ETrue;
   927             }
   928         }
   929 
   930  	thisLength = (thisLength > KMaxBufSize) ? KMaxBufSize : thisLength;
   931 
   932    	iDataBuf.SetLength(thisLength);
   933    	TPtr8 readBuf = iDataBuf.LeftTPtr(iDataBuf.Length());
   934     iTransport->SetupDataOut(readBuf);
   935     return wait ? KErrNotReady : KErrCompletion;
   936 	}
   937 
   938 
   939 /**
   940 Command Parser for the MODE SENSE(06) command (0x1A)
   941 
   942 @return ETrue if successful.
   943 */
   944 TBool CScsiServerProtocol::HandleModeSense6(const TScsiServerReq& aRequest)
   945 	{
   946     __MSFNLOG
   947 	const TScsiServerModeSense6Req& request = static_cast<const TScsiServerModeSense6Req&>(aRequest);
   948 
   949 	TScsiServerModeSense6Resp response;
   950     response.SetAllocationLength(request.iAllocationLength);
   951 
   952 	if (request.iPageCode != TScsiServerModeSense6Req::KAllPages ||
   953         request.iPageControl == TScsiServerModeSense6Req::EChangeableValues)
   954 		{
   955 		__PRINT(_L("TSenseInfo::EIllegalRequest,TSenseInfo::EInvalidFieldInCdb"));
   956 		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest,TSenseInfo::EInvalidFieldInCdb);
   957 		return EFalse;
   958 		}
   959 	if (request.iPageControl != TScsiServerModeSense6Req::EDefaultValues)
   960 		{
   961 		//check if drive write protected
   962 		CMassStorageDrive* drive = GetCheckDrive();
   963 		if (drive == NULL)
   964 			{
   965 			__PRINT(_L("drive == null"));
   966 			return EFalse;
   967 			}
   968 
   969 #ifdef MSDC_TESTMODE
   970     if (iTestParser)
   971         {
   972         response.SetWp(iTestParser->WriteProtect());
   973         }
   974 #else
   975         response.SetWp(drive->MediaParams().IsWriteProtected());
   976 #endif
   977         }
   978 
   979     response.Encode(iCommandBuf);
   980 
   981 	TPtrC8 writeBuf = iCommandBuf;
   982 	iTransport->SetupDataIn(writeBuf);
   983 	return iSenseInfo.SenseOk();
   984 	}