userlibandfileserver/fileserver/smassstorage/rwdrivethread.cpp
changeset 286 48e57fb1237e
parent 0 a41df078684a
equal deleted inserted replaced
285:ff5437e4337c 286:48e57fb1237e
     1 // Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
     1 // Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     3 // This component and the accompanying materials are made available
     4 // under the terms of the License "Eclipse Public License v1.0"
     4 // under the terms of the License "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
    11 // Contributors:
    11 // Contributors:
    12 //
    12 //
    13 // Description:
    13 // Description:
    14 //
    14 //
    15 
    15 
    16 #include "scsiprot.h"
    16 
       
    17 #include <e32std.h>
       
    18 #include "smassstorage.h"
       
    19 #include "mprotocol.h"
       
    20 #include "scsiprot.h"       // KMaxBufSize
       
    21 #include "drivemanager.h"
    17 #include "usbmsshared.h"
    22 #include "usbmsshared.h"
    18 #include "rwdrivethread.h"
    23 #include "rwdrivethread.h"
    19 #include "massstoragedebug.h"
    24 
    20 
    25 
    21 // ---
    26 #include "OstTraceDefinitions.h"
    22 
    27 #ifdef OST_TRACE_COMPILER_IN_USE
    23 #ifdef PRINT_MSDC_MULTITHREADED_READ_INFO
    28 #include "rwdrivethreadTraces.h"
    24 #define __MT_READ_PRINT(t) {RDebug::Print(t);}
    29 #endif
    25 #define __MT_READ_PRINT1(t,a) {RDebug::Print(t,a);}
    30 
    26 #define __MT_READ_PRINT2(t,a,b) {RDebug::Print(t,a,b);}
    31 
    27 #else
    32 #ifdef MSDC_MULTITHREADED
    28 #define __MT_READ_PRINT(t)
       
    29 #define __MT_READ_PRINT1(t,a)
       
    30 #define __MT_READ_PRINT2(t,a,b)
       
    31 #endif // PRINT_MSDC_MULTITHREADED_READ_INFO
       
    32 
       
    33 
       
    34 #ifdef MSDC_MULTITHREADED 
       
    35 
    33 
    36 TBlockDesc::TBlockDesc()
    34 TBlockDesc::TBlockDesc()
    37 	:iBuf((TUint8 *)NULL,0,0)
    35     :iBuf((TUint8 *)NULL,0,0)
    38 	{
    36     {
    39 	}
    37     }
    40 
    38 
    41 void TBlockDesc::SetPtr(TPtr8& aDes)
    39 void TBlockDesc::SetPtr(TPtr8& aDes)
    42 	{
    40     {
    43 	iBuf.Set(aDes);
    41     iBuf.Set(aDes);
    44 	}
    42     }
    45 
    43 
    46 
    44 
    47 TBlockDescBuffer::TBlockDescBuffer()
    45 TBlockDescBuffer::TBlockDescBuffer()
    48 	{ 
    46     {
    49 	iDescReadPtr = &iDesc1;
    47     iDescReadPtr = &iDesc1;
    50 	iDescWritePtr = &iDesc2;
    48     iDescWritePtr = &iDesc2;
    51 	}
    49     }
    52 
    50 
    53 void TBlockDescBuffer::SetUpReadBuf(TPtr8& aDes1, TPtr8& aDes2)
    51 void TBlockDescBuffer::SetUpReadBuf(TPtr8& aDes1, TPtr8& aDes2)
    54 	{
    52     {
    55 	iDesc1.SetPtr(aDes1);
    53     iDesc1.SetPtr(aDes1);
    56 	iDesc2.SetPtr(aDes2);
    54     iDesc2.SetPtr(aDes2);
    57 	iDescReadPtr = &iDesc1;
    55     iDescReadPtr = &iDesc1;
    58 	iDescWritePtr = &iDesc2;
    56     iDescWritePtr = &iDesc2;
    59 	}
    57     }
    60 
    58 
    61 
    59 
    62 //-----------------------------------------------
    60 //-----------------------------------------------
    63 
    61 
    64 /**
    62 /**
    67 @param aName The name to be assigned to this thread.
    65 @param aName The name to be assigned to this thread.
    68 @param aThreadFunction Function to be called when thread is initially scheduled.
    66 @param aThreadFunction Function to be called when thread is initially scheduled.
    69 @param aOwner Pointer to the object owning the thread. Used as the parameter to aThreadFunction.
    67 @param aOwner Pointer to the object owning the thread. Used as the parameter to aThreadFunction.
    70 */
    68 */
    71 CThreadContext* CThreadContext::NewL(const TDesC& aName,
    69 CThreadContext* CThreadContext::NewL(const TDesC& aName,
    72 									 TThreadFunction aThreadFunction,
    70                                      TThreadFunction aThreadFunction,
    73 									 TAny* aOwner)
    71                                      TAny* aOwner)
    74 	{
    72     {
    75 	__FNLOG("CThreadContext::NewL");
    73     CThreadContext* self = new (ELeave) CThreadContext();
    76 	CThreadContext* self = new (ELeave) CThreadContext();
    74     CleanupStack::PushL(self);
    77 	CleanupStack::PushL(self);
    75     self->ConstructL(aName, aThreadFunction, aOwner);
    78 	self->ConstructL(aName, aThreadFunction, aOwner);
    76     CleanupStack::Pop();
    79 	CleanupStack::Pop();
    77     return self;
    80 	return self;
    78     }
    81 	}
       
    82 
    79 
    83 /**
    80 /**
    84 Construct a CThreadContext object
    81 Construct a CThreadContext object
    85 
    82 
    86 @param aName The name to be assigned to this thread.
    83 @param aName The name to be assigned to this thread.
    87 @param aThreadFunction Function to be called when thread is initially scheduled.
    84 @param aThreadFunction Function to be called when thread is initially scheduled.
    88 @param aOwner Pointer to the object owning the thread. Used as the parameter to aThreadFunction.
    85 @param aOwner Pointer to the object owning the thread. Used as the parameter to aThreadFunction.
    89 */
    86 */
    90 void CThreadContext::ConstructL(const TDesC& aName,
    87 void CThreadContext::ConstructL(const TDesC& aName,
    91 								TThreadFunction aThreadFunction,
    88                                 TThreadFunction aThreadFunction,
    92 								TAny* aOwner)
    89                                 TAny* aOwner)
    93 	{
    90     {
    94 	__FNLOG("CThreadContext::ConstructL");
    91     OstTrace0(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_10, "Creating Critical Section");
    95 	__PRINT(_L("Creating Critical Section"));
    92     User::LeaveIfError(iCritSect.CreateLocal());
    96 	User::LeaveIfError(iCritSect.CreateLocal());
    93     OstTrace0(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_11, "Creating RThread");
    97 	__PRINT(_L("Creating RThread"));
    94 
    98 
    95     TUint serial(0); // Used to retry creation of a thread in case
    99 	TUint serial(0); // Used to retry creation of a thread in case
    96                      // one with the same name already exists
   100 					 // one with the same name already exists
    97 
   101 
    98     RBuf threadName;
   102 	RBuf threadName;
    99     threadName.CreateMaxL(aName.Length() + 8);
   103 	threadName.CreateMaxL(aName.Length() + 8);
   100     CleanupClosePushL(threadName);
   104 	CleanupClosePushL(threadName);
   101     threadName = aName;
   105 	threadName = aName;
   102 
   106 
   103     TInt err;
   107 	TInt err;
   104     for (;;)
   108 	for (;;)
   105         {
   109 		{
   106         err = iThread.Create(threadName, aThreadFunction, 0x1000, NULL, aOwner);
   110 		err = iThread.Create(threadName, aThreadFunction, 0x1000, NULL, aOwner);
   107         OstTraceData(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_13,
   111 		__PRINT2(_L("CThreadContext::ConstructL Created thread %S err=%d"), &threadName, err);
   108                      "CThreadContext::ConstructL Created thread %s err=%d", threadName.Ptr(), threadName.Length());
       
   109         OstTrace1(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_14,
       
   110                      "err=%d", err);
       
   111 
   112 
   112 
   113         // for a restart wait and retry until old thread is gone
   113         // for a restart wait and retry until old thread is gone
   114 		if (err == KErrAlreadyExists)
   114         if (err == KErrAlreadyExists)
   115 			{
   115             {
   116 			User::After(10 * 1000);     // 10 mS
   116             User::After(10 * 1000);     // 10 mS
   117 			threadName = aName;
   117             threadName = aName;
   118 			threadName.AppendNumFixedWidth(serial, EDecimal, 8);
   118             threadName.AppendNumFixedWidth(serial, EDecimal, 8);
   119 			++serial;
   119             ++serial;
   120 			}
   120             }
   121 		else
   121         else
   122 			{
   122             {
   123 			break;
   123             break;
   124 			}
   124             }
   125 		}
   125         }
   126 
   126 
   127     User::LeaveIfError(err);
   127     User::LeaveIfError(err);
   128     CleanupStack::Pop(); // threadName
   128     CleanupStack::Pop(); // threadName
   129     threadName.Close();
   129     threadName.Close();
   130 
   130 
   131 	// set priority
   131     // set priority
   132 	iThread.SetPriority(EPriorityMore);
   132     iThread.SetPriority(EPriorityMore);
   133 	}
   133     }
   134 
   134 
   135 
   135 
   136 /**
   136 /**
   137 Construct a CThreadContext object
   137 Construct a CThreadContext object
   138 */
   138 */
   139 CThreadContext::CThreadContext()
   139 CThreadContext::CThreadContext()
   140 	:
   140     :
   141 	iError(KErrNone)
   141     iError(KErrNone)
   142 	{
   142     {
   143 	__FNLOG("CThreadContext::CThreadContext");
   143     }
   144 	}
       
   145 
   144 
   146 /**
   145 /**
   147 Destructor
   146 Destructor
   148 */
   147 */
   149 CThreadContext::~CThreadContext()
   148 CThreadContext::~CThreadContext()
   150 	{
   149     {
   151 	__FNLOG("CThreadContext::~CThreadContext");
   150     OstTrace0(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_20, "Closing Critical Section");
   152 	__PRINT(_L("Closing Critical Section"));
   151     iCritSect.Close();
   153 	iCritSect.Close();
   152     OstTrace0(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_21, "Killing ThreadContext");
   154 	__PRINT(_L("Killing ThreadContext"));
   153     iThread.Kill(0);
   155 	iThread.Kill(0);
   154     OstTrace0(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_22, "Closing ThreadContext");
   156 	__PRINT(_L("Closing ThreadContext"));
   155     iThread.Close();
   157 	iThread.Close();
   156     }
   158 	}
       
   159 
   157 
   160 //-----------------------------------------------
   158 //-----------------------------------------------
   161 
   159 
   162 /**
   160 /**
   163 Construct a CWriteDriveThread object
   161 Construct a CWriteDriveThread object
   164 */
   162 */
   165 CWriteDriveThread* CWriteDriveThread::NewL()
   163 CWriteDriveThread* CWriteDriveThread::NewL()
   166 	{
   164     {
   167 	__FNLOG("CWriteDriveThread::NewL");
   165     CWriteDriveThread* self = new (ELeave) CWriteDriveThread();
   168 	CWriteDriveThread* self = new (ELeave) CWriteDriveThread();
   166     CleanupStack::PushL(self);
   169 	CleanupStack::PushL(self);
   167     self->ConstructL();
   170 	self->ConstructL();
   168     CleanupStack::Pop();
   171 	CleanupStack::Pop();
   169     return self;
   172 	return self;
   170     }
   173 	}
       
   174 
   171 
   175 /**
   172 /**
   176 Construct a CWriteDriveThread object
   173 Construct a CWriteDriveThread object
   177 */
   174 */
   178 void CWriteDriveThread::ConstructL()
   175 void CWriteDriveThread::ConstructL()
   179 	{
   176     {
   180 	__FNLOG("CWriteDriveThread::ConstructL");
   177     TBuf<16> name = _L("MassStorageWrite");
   181 	TBuf<16> name = _L("MassStorageWrite");
   178     iThreadContext = CThreadContext::NewL(name, ThreadFunction, this);
   182 	iThreadContext = CThreadContext::NewL(name, ThreadFunction, this);
   179     // There are two free pointers to start with so initialise the semaphore with 1
   183 	// There are two free pointers to start with so initialise the semaphore with 1
   180     User::LeaveIfError(iProducerSem.CreateLocal(1));
   184 	User::LeaveIfError(iProducerSem.CreateLocal(1));
   181     User::LeaveIfError(iConsumerSem.CreateLocal(0));
   185 	User::LeaveIfError(iConsumerSem.CreateLocal(0));
   182 
   186 	
   183     iThreadContext->Resume();
   187 	iThreadContext->Resume();
   184     }
   188 	}
       
   189 
   185 
   190 /**
   186 /**
   191 Construct a CWriteDriveThread object
   187 Construct a CWriteDriveThread object
   192 */
   188 */
   193 CWriteDriveThread::CWriteDriveThread() 
   189 CWriteDriveThread::CWriteDriveThread()
   194 	: iIsCommandWrite10(EFalse)
   190     : iIsCommandWrite10(EFalse)
   195 	{
   191     {
   196 	__FNLOG("CWriteDriveThread::CWriteDriveThread");
   192     }
   197 	}
       
   198 
   193 
   199 /**
   194 /**
   200 Destructor
   195 Destructor
   201 */
   196 */
   202 CWriteDriveThread::~CWriteDriveThread()
   197 CWriteDriveThread::~CWriteDriveThread()
   203 	{
   198     {
   204 	__FNLOG("CWriteDriveThread::~CWriteDriveThread");
   199     delete iThreadContext;
   205 	delete iThreadContext;
   200     }
   206 	}
       
   207 
   201 
   208 /**
   202 /**
   209 This function is called when the thread is initially scheduled.
   203 This function is called when the thread is initially scheduled.
   210 
   204 
   211 @param aSelf Pointer to self to facilitate call to member method.
   205 @param aSelf Pointer to self to facilitate call to member method.
   212 */
   206 */
   213 TInt CWriteDriveThread::ThreadFunction(TAny* aSelf)
   207 TInt CWriteDriveThread::ThreadFunction(TAny* aSelf)
   214 	{
   208     {
   215 	__FNLOG("CWriteDriveThread::ThreadFunction");
   209     CWriteDriveThread* self = static_cast<CWriteDriveThread*>(aSelf);
   216 	CWriteDriveThread* self = static_cast<CWriteDriveThread*>(aSelf);
   210     return self->WriteToDrive();
   217 	return self->WriteToDrive();
   211     }
   218 	}
       
   219 
   212 
   220 /**
   213 /**
   221 Writes the data pointed to by iDescWritePtr to the drive.
   214 Writes the data pointed to by iDescWritePtr to the drive.
   222 */
   215 */
   223 TInt CWriteDriveThread::WriteToDrive()
   216 TInt CWriteDriveThread::WriteToDrive()
   224 	{
   217     {
   225 	__FNLOG("\tCWriteDriveThread::WriteToDrive");
   218     // One-off convenience variable assignment
   226 
   219     TBlockDesc* &desc = iThreadContext->iBuffer.iDescWritePtr;
   227 	// One-off convenience variable assignment
   220 
   228 	TBlockDesc* &desc = iThreadContext->iBuffer.iDescWritePtr;
   221     for(;;)
   229 	
   222         {
   230 	for(;;)
   223         iConsumerSem.Wait();
   231 		{
   224         OstTrace0(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_30, "Waiting on Write CS...");
   232 		iConsumerSem.Wait();
   225         iThreadContext->iCritSect.Wait();
   233 		__PRINT(_L("\tWaiting on Write CS..."));
   226         // +++ WRITE CS STARTS HERE +++
   234 		iThreadContext->iCritSect.Wait();
   227         OstTrace1(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_31,
   235 		// +++ WRITE CS STARTS HERE +++
   228                   "Now using as write buffer: iBuf%d", iThreadContext->iBuffer.GetBufferNumber(&desc->iBuf));
   236 		__PRINT1(_L("\tNow using as write buffer: iBuf%d"), iThreadContext->iBuffer.GetBufferNumber(&desc->iBuf));
   229         OstTrace1(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_32,
   237 #ifdef MEASURE_AND_DISPLAY_WRITE_TIME
   230                   "SCSI: writing %d bytes", desc->iBuf.Length());
   238 		RDebug::Print(_L("\tSCSI: writing %d bytes\n"), desc->iBuf.Length());
   231         // Write buffer to disk
   239 		TTime t0, t1;
   232         iThreadContext->iError = iThreadContext->iDrive->Write(desc->iByteOffset, desc->iBuf,iThreadContext->iDrive->IsWholeMediaAccess());
   240 		t0.HomeTime();
   233 
   241 #else
   234         iCallback((TUint8*) (desc->iBuf.Ptr()), iCallbackParameter);
   242 		__PRINT1(_L("\tSCSI: writing %d bytes\n"), desc->iBuf.Length());
   235         iWriteCounter--;
   243 #endif
   236         __ASSERT_DEBUG(iWriteCounter >= 0, User::Panic(KUsbMsSvrPncCat, EMsThreadWriteToDrive));
   244 		// Write buffer to disk
   237 
   245 
   238         OstTrace0(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_33, "Signalling Write CS");
   246 #ifdef INJECT_ERROR
   239         iThreadContext->iCritSect.Signal();
   247 		if (desc->iBuf[0] == '2')
   240         // +++ WRITE CS ENDS HERE +++
   248 		{
   241         iProducerSem.Signal();
   249 			desc->iBuf[0] = 'x';
   242         }
   250 			RDebug::Printf("Injecting error");
   243     }
   251 		}
   244 
   252 
   245 /**
   253 		
   246 Initiates writing data pointed to by iReadBuf to the drive and resumes the thread. Writing
   254 		RDebug::Printf("%08lx %x [%x] [%x]", desc->iByteOffset, desc->iBuf.Length(), 
       
   255 			desc->iBuf[0],
       
   256 			desc->iBuf[desc->iBuf.Length()-1]);
       
   257 #endif
       
   258 
       
   259 		iThreadContext->iError = iThreadContext->iDrive->Write(desc->iByteOffset, desc->iBuf,iThreadContext->iDrive->IsWholeMediaAccess());
       
   260 #ifdef INJECT_ERROR
       
   261 		if (desc->iBuf[0] == 'x')
       
   262 		{
       
   263 			iThreadContext->iError = KErrUnknown;
       
   264 		}
       
   265 #endif
       
   266 
       
   267 #ifdef MEASURE_AND_DISPLAY_WRITE_TIME
       
   268 		t1.HomeTime();
       
   269 		const TTimeIntervalMicroSeconds time = t1.MicroSecondsFrom(t0);
       
   270 		const TUint time_ms = I64LOW(time.Int64() / 1000);
       
   271 		RDebug::Print(_L("SCSI: write took %d ms\n"), time_ms);
       
   272 #endif
       
   273 		iCallback((TUint8*) (desc->iBuf.Ptr()), iCallbackParameter);
       
   274 		iWriteCounter--;
       
   275 		ASSERT(iWriteCounter >= 0);
       
   276 
       
   277 		__PRINT(_L("\tSignalling Write CS"));
       
   278 		iThreadContext->iCritSect.Signal();
       
   279 		// +++ WRITE CS ENDS HERE +++
       
   280 		iProducerSem.Signal();
       
   281 		}
       
   282 	}
       
   283 
       
   284 /**
       
   285 Initiates writing data pointed to by iReadBuf to the drive and resumes the thread. Writing 
       
   286 is completed by the ThreadFunction when the thread is resumed.
   247 is completed by the ThreadFunction when the thread is resumed.
   287 
   248 
   288 @param aDrive Drive to write to.
   249 @param aDrive Drive to write to.
   289 @param aOffset Write offset.
   250 @param aOffset Write offset.
   290 */
   251 */
   291 TInt CWriteDriveThread::WriteDriveData(CMassStorageDrive* aDrive, const TInt64& aOffset, TPtrC8& aDes, ProcessWriteCompleteFunc aFunc, TAny* aPtr)
   252 TInt CWriteDriveThread::WriteDriveData(CMassStorageDrive* aDrive, const TInt64& aOffset, TPtrC8& aDes, ProcessWriteCompleteFunc aFunc, TAny* aPtr)
   292 	{
   253     {
   293 	// Check error code from previous write
   254     // Check error code from previous write
   294 	const TInt r = iThreadContext->iError;
   255     const TInt r = iThreadContext->iError;
   295 	if (r != KErrNone)
   256     if (r != KErrNone)
   296 		{
   257         {
   297 		__PRINT1(_L("Error after previous write = 0x%x \n"), r);
   258         OstTrace1(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_40, "Error after previous write = %d", r);
   298 		return KErrAbort;
   259         return KErrAbort;
   299         }
   260         }
   300 
   261 
   301 	// Swap the two buffer pointers
   262     // Swap the two buffer pointers
   302 	iProducerSem.Wait();
   263     iProducerSem.Wait();
   303 	__PRINT(_L("Waiting on Write CS..."));
   264     OstTrace0(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_41, "Waiting on Write CS...");
   304 	// +++ WRITE CS STARTS HERE +++
   265     // +++ WRITE CS STARTS HERE +++
   305 	iThreadContext->iCritSect.Wait();
   266     iThreadContext->iCritSect.Wait();
   306 
   267 
   307 	// New DB First read into the iDescReadPtr pointer,
   268     // New DB First read into the iDescReadPtr pointer,
   308 	// then swap,so that write pointer points to correct location, as the ptr pointed to by iDescWritePtr is what is written from in WriteToDrive 
   269     // then swap,so that write pointer points to correct location, as the ptr pointed to by iDescWritePtr is what is written from in WriteToDrive
   309 	iThreadContext->iBuffer.iDescReadPtr->iBuf.Set((TUint8*)aDes.Ptr(), aDes.Length(), KMaxBufSize );
   270     iThreadContext->iBuffer.iDescReadPtr->iBuf.Set((TUint8*)aDes.Ptr(), aDes.Length(), KMaxBufSize);
   310 	
   271 
   311 	iCallback = aFunc;
   272     iCallback = aFunc;
   312 	iCallbackParameter = aPtr;
   273     iCallbackParameter = aPtr;
   313 
   274 
   314 	iWriteCounter++;
   275     iWriteCounter++;
   315 	iThreadContext->iBuffer.SwapDesc();
   276     iThreadContext->iBuffer.SwapDesc();
   316 	// Prepare variables for next write
   277     // Prepare variables for next write
   317 	iThreadContext->iDrive = aDrive;
   278     iThreadContext->iDrive = aDrive;
   318 	iThreadContext->iBuffer.iDescWritePtr->iByteOffset = aOffset;
   279     iThreadContext->iBuffer.iDescWritePtr->iByteOffset = aOffset;
   319 	// +++ WRITE CS ENDS HERE +++
   280     // +++ WRITE CS ENDS HERE +++
   320 	__PRINT(_L("Signalling Write CS..."));
   281     OstTrace0(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_42, "Signalling Write CS...");
   321 	iThreadContext->iCritSect.Signal();
   282     iThreadContext->iCritSect.Signal();
   322 
   283 
   323 	iConsumerSem.Signal();
   284     iConsumerSem.Signal();
   324 	return KErrNone;
   285     return KErrNone;
   325 }
   286 }
   326 
   287 
   327 
   288 
   328 void CWriteDriveThread::WaitForWriteEmpty()
   289 void CWriteDriveThread::WaitForWriteEmpty()
   329 {
   290 {
   330 	while(iWriteCounter > 0)
   291     while(iWriteCounter > 0)
   331 		{
   292         {
   332 		User::After(100);
   293         User::After(100);
   333 		}
   294         }
   334 }
   295 }
   335 
   296 
   336 // Check if the target address range was recently written to, this is to force a
   297 // Check if the target address range was recently written to, this is to force a
   337 // cache miss when reading from the same sectors that were just written. 
   298 // cache miss when reading from the same sectors that were just written.
   338 // Optimisation note: this is only needed if the read precache was started
   299 // Optimisation note: this is only needed if the read precache was started
   339 // before the write was completed.
   300 // before the write was completed.
   340 TBool CWriteDriveThread::IsRecentlyWritten(TInt64 aOffset, TInt aLength)
   301 TBool CWriteDriveThread::IsRecentlyWritten(TInt64 aOffset, TInt aLength)
   341 {
   302 {
   342 	ASSERT(iWriteCounter == 0);
   303     __ASSERT_DEBUG(iWriteCounter == 0, User::Panic(KUsbMsSvrPncCat, EMsThreadIsRecentlyWritten));
   343 	if (iIsCommandWrite10) //If the previous command is Write10, then discard pre-read as the same buffers are used and will be over written by Write10 
   304     if (iIsCommandWrite10) //If the previous command is Write10, then discard pre-read as the same buffers are used and will be over written by Write10
   344 		return ETrue;
   305         return ETrue;
   345 	if(aOffset <= iThreadContext->iBuffer.iDescReadPtr->iByteOffset &&
   306     if(aOffset <= iThreadContext->iBuffer.iDescReadPtr->iByteOffset &&
   346 			aOffset + aLength >= iThreadContext->iBuffer.iDescReadPtr->iByteOffset)
   307             aOffset + aLength >= iThreadContext->iBuffer.iDescReadPtr->iByteOffset)
   347 		return ETrue;
   308         return ETrue;
   348 	if(aOffset >= iThreadContext->iBuffer.iDescReadPtr->iByteOffset &&
   309     if(aOffset >= iThreadContext->iBuffer.iDescReadPtr->iByteOffset &&
   349 			aOffset <= iThreadContext->iBuffer.iDescReadPtr->iByteOffset + iThreadContext->iBuffer.iDescReadPtr->iLength)
   310             aOffset <= iThreadContext->iBuffer.iDescReadPtr->iByteOffset + iThreadContext->iBuffer.iDescReadPtr->iLength)
   350 		return ETrue;
   311         return ETrue;
   351 	if(aOffset <= iThreadContext->iBuffer.iDescWritePtr->iByteOffset &&
   312     if(aOffset <= iThreadContext->iBuffer.iDescWritePtr->iByteOffset &&
   352 			aOffset + aLength >= iThreadContext->iBuffer.iDescReadPtr->iByteOffset)
   313             aOffset + aLength >= iThreadContext->iBuffer.iDescReadPtr->iByteOffset)
   353 		return ETrue;
   314         return ETrue;
   354 	if(aOffset >= iThreadContext->iBuffer.iDescWritePtr->iByteOffset &&
   315     if(aOffset >= iThreadContext->iBuffer.iDescWritePtr->iByteOffset &&
   355 			aOffset <= iThreadContext->iBuffer.iDescReadPtr->iByteOffset + iThreadContext->iBuffer.iDescReadPtr->iLength)
   316             aOffset <= iThreadContext->iBuffer.iDescReadPtr->iByteOffset + iThreadContext->iBuffer.iDescReadPtr->iLength)
   356 		return ETrue;
   317         return ETrue;
   357 	return EFalse;
   318     return EFalse;
   358 }
   319 }
   359 
   320 
   360 //-----------------------------------------------
   321 //-----------------------------------------------
   361 
   322 
   362 /**
   323 /**
   363 Construct a CReadDriveThread object
   324 Construct a CReadDriveThread object
   364 */
   325 */
   365 CReadDriveThread* CReadDriveThread::NewL()
   326 CReadDriveThread* CReadDriveThread::NewL()
   366 	{
   327     {
   367 	__FNLOG("CReadDriveThread::NewL");
   328     CReadDriveThread* self = new (ELeave) CReadDriveThread();
   368 	CReadDriveThread* self = new (ELeave) CReadDriveThread();
   329     CleanupStack::PushL(self);
   369 	CleanupStack::PushL(self);
   330     self->ConstructL();
   370 	self->ConstructL();
   331     CleanupStack::Pop();
   371 	CleanupStack::Pop();
   332     return self;
   372 	return self;
   333     }
   373 	}
       
   374 
   334 
   375 /**
   335 /**
   376 Construct a CReadDriveThread object
   336 Construct a CReadDriveThread object
   377 
   337 
   378 @param aName The name to be assigned to this thread.
   338 @param aName The name to be assigned to this thread.
   379 @pram aThreadFunction Function to be called when thread is initially scheduled.
   339 @pram aThreadFunction Function to be called when thread is initially scheduled.
   380 */
   340 */
   381 void CReadDriveThread::ConstructL()
   341 void CReadDriveThread::ConstructL()
   382 	{
   342     {
   383 	__FNLOG("CReadDriveThread::ConstructL");
   343     TBuf<15> name = _L("MassStorageRead");
   384 	TBuf<15> name = _L("MassStorageRead");
   344     iThreadContext = CThreadContext::NewL(name, ThreadFunction, this);
   385 	iThreadContext = CThreadContext::NewL(name, ThreadFunction, this);
   345     }
   386 	}
       
   387 
   346 
   388 /**
   347 /**
   389 Construct a CReadDriveThread object
   348 Construct a CReadDriveThread object
   390 */
   349 */
   391 CReadDriveThread::CReadDriveThread()
   350 CReadDriveThread::CReadDriveThread()
   392 	:
   351     :
   393 	iThreadRunning(EFalse)
   352     iThreadRunning(EFalse)
   394 	{
   353     {
   395 	__FNLOG("CReadDriveThread::CReadDriveThread");
   354     }
   396 	}
       
   397 
   355 
   398 /**
   356 /**
   399 Destructor
   357 Destructor
   400 */
   358 */
   401 CReadDriveThread::~CReadDriveThread()
   359 CReadDriveThread::~CReadDriveThread()
   402 	{
   360     {
   403 	__FNLOG("CReadDriveThread::~CReadDriveThread");
   361     delete iThreadContext;
   404 	delete iThreadContext;
   362     }
   405 	}
       
   406 
   363 
   407 /**
   364 /**
   408 This function is called when the thread is initially scheduled.
   365 This function is called when the thread is initially scheduled.
   409 
   366 
   410 @param aSelf Pointer to self to facilitate call to member method.
   367 @param aSelf Pointer to self to facilitate call to member method.
   411 */
   368 */
   412 TInt CReadDriveThread::ThreadFunction(TAny* aSelf)
   369 TInt CReadDriveThread::ThreadFunction(TAny* aSelf)
   413 	{
   370     {
   414 	__FNLOG("CReadDriveThread::ThreadFunction");
   371     CReadDriveThread* self = static_cast<CReadDriveThread*>(aSelf);
   415 	CReadDriveThread* self = static_cast<CReadDriveThread*>(aSelf);
   372     return self->ReadFromDrive();
   416 	return self->ReadFromDrive();
   373     }
   417 	}
       
   418 
   374 
   419 /**
   375 /**
   420 Reads data from the drive with iOffset and iReadLength into memory pointer iReadBuffer
   376 Reads data from the drive with iOffset and iReadLength into memory pointer iReadBuffer
   421 and suspends the thread.
   377 and suspends the thread.
   422 */
   378 */
   423 TInt CReadDriveThread::ReadFromDrive()
   379 TInt CReadDriveThread::ReadFromDrive()
   424 	{
   380     {
   425 	__FNLOG("\tCReadDriveThread::ReadFromDrive");
   381     // One-off convenience variable assignment
   426 
   382     TBlockDesc* &desc = iThreadContext->iBuffer.iDescWritePtr;
   427 	// One-off convenience variable assignment
   383 
   428 	TBlockDesc* &desc = iThreadContext->iBuffer.iDescWritePtr;
   384     for (;;)
   429 
   385         {
   430 	for (;;)
   386         OstTrace0(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_50, "Waiting on Read CS...");
   431 		{
   387         iThreadContext->iCritSect.Wait();
   432 		__PRINT(_L("\tWaiting on Read CS..."));
   388         // +++ READ CS STARTS HERE +++
   433 		iThreadContext->iCritSect.Wait();
   389         iThreadRunning = ETrue;
   434 		// +++ READ CS STARTS HERE +++
   390         iCompleted = EFalse;
   435 		iThreadRunning = ETrue;
   391 
   436 		iCompleted = EFalse;
   392         OstTrace1(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_51,
   437 
   393                   "\tNow using as read buffer: iBuf%d", iThreadContext->iBuffer.GetBufferNumber(&desc->iBuf));
   438 		__PRINT1(_L("\tNow using as read buffer: iBuf%d"), iThreadContext->iBuffer.GetBufferNumber(&desc->iBuf));
   394         OstTrace1(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_52,
   439  
   395                   "\tSCSI: reading %d bytes", desc->iBuf.Length());
   440 #ifdef MEASURE_AND_DISPLAY_READ_TIME
   396 
   441 		RDebug::Print(_L("\tSCSI: reading %d bytes\n"), desc->iBuf.Length());
   397         // Fill read buffer from disk
   442 		TTime t0, t1;
   398         iThreadContext->iError = iThreadContext->iDrive->Read(desc->iByteOffset,
   443 		t0.HomeTime();
   399                                                               desc->iLength,
   444 #else
   400                                                               desc->iBuf,
   445 		__PRINT1(_L("\tSCSI: reading %d bytes\n"), desc->iBuf.Length());
   401                                                               iThreadContext->iDrive->IsWholeMediaAccess());
   446 #endif
   402 
   447 		// Fill read buffer from disk
   403         iCompleted = ETrue;
   448 		iThreadContext->iError = iThreadContext->iDrive->Read(desc->iByteOffset,
   404         iThreadRunning = EFalse;
   449 															  desc->iLength,
   405         OstTrace0(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_53, "Signalling Read CS");
   450 															  desc->iBuf,
   406         // +++ READ CS ENDS HERE +++
   451 															  iThreadContext->iDrive->IsWholeMediaAccess());
   407         iThreadContext->iCritSect.Signal();
   452 
   408         // Suspend self
   453 #ifdef MEASURE_AND_DISPLAY_READ_TIME
   409         OstTrace0(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_54, "Suspending Read Thread");
   454 		t1.HomeTime();
   410         RThread().Suspend();
   455 		const TTimeIntervalMicroSeconds time = t1.MicroSecondsFrom(t0);
   411         }
   456 		const TUint time_ms = I64LOW(time.Int64() / 1000);
   412     }
   457 		RDebug::Print(_L("SCSI: read took %d ms\n"), time_ms);
   413 
   458 #endif
   414 /**
   459 
   415 Client read request of a data block from the specified drive.
   460 		iCompleted = ETrue;
       
   461 		iThreadRunning = EFalse;
       
   462 		__PRINT(_L("\tSignalling Read CS"));
       
   463 		// +++ READ CS ENDS HERE +++
       
   464 		iThreadContext->iCritSect.Signal();
       
   465 		// Suspend self
       
   466 		__PRINT(_L("\tSuspending Read Thread"));
       
   467 		RThread().Suspend();
       
   468 		}
       
   469 	}
       
   470 
       
   471 /**
       
   472 Client read request of a data block from the specified drive. 
       
   473 If there is no pre-read data that matches the requested Offset and Length then the drive
   416 If there is no pre-read data that matches the requested Offset and Length then the drive
   474 is read and the next pre-read is setup. If there is matching pre-read data available then
   417 is read and the next pre-read is setup. If there is matching pre-read data available then
   475 the next pre-read is setup. Finishes by resuming the thread and the ThreadFunciton runs.
   418 the next pre-read is setup. Finishes by resuming the thread and the ThreadFunciton runs.
   476 
   419 
   477 @param aDrive Drive to read from.
   420 @param aDrive Drive to read from.
   478 @param aOffset Read offset
   421 @param aOffset Read offset
   479 @param aLength Length 
   422 @param aLength Length
   480 */
   423 */
   481 TBool CReadDriveThread::ReadDriveData(CMassStorageDrive* aDrive,
   424 TBool CReadDriveThread::ReadDriveData(CMassStorageDrive* aDrive,
   482 									  const TInt64& aOffset,
   425                                       const TInt64& aOffset,
   483 									  TUint32 aLength,
   426                                       TUint32 aLength,
   484 									  TBool aIgnoreCache)
   427                                       TBool aIgnoreCache)
   485 	{
   428     {
   486 	__MT_READ_PRINT2(_L("\nRead10: offs %ld len %d"), aOffset, aLength);
   429     OstTraceExt2(TRACE_SMASSSTORAGE_MEDIADB, CTHREADCONTEXT_60, "Read10: offs %ld len %d", aOffset, aLength);
   487 
   430 
   488 	__PRINT(_L("Waiting on Read CS..."));
   431     OstTrace0(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_61, "Waiting on Read CS...");
   489 	iThreadContext->iCritSect.Wait();
   432     iThreadContext->iCritSect.Wait();
   490 	// +++ READ CS STARTS HERE +++
   433     // +++ READ CS STARTS HERE +++
   491 	__ASSERT_DEBUG(!iThreadRunning, User::Panic(_L("MSDC-THREAD"), 666));
   434     __ASSERT_DEBUG(!iThreadRunning, User::Panic(KUsbMsSvrPncCat, EMsThreadReadDriveThread));
   492 
   435 
   493 	TBlockDesc* &desc = iThreadContext->iBuffer.iDescReadPtr;
   436     TBlockDesc* &desc = iThreadContext->iBuffer.iDescReadPtr;
   494 	TBlockDesc* &bgDesc = iThreadContext->iBuffer.iDescWritePtr;
   437     TBlockDesc* &bgDesc = iThreadContext->iBuffer.iDescWritePtr;
   495 
   438 
   496 	if ((!aIgnoreCache) &&
   439     if ((!aIgnoreCache) &&
   497 		(iCompleted) &&
   440         (iCompleted) &&
   498 		(iThreadContext->iError == KErrNone) &&
   441         (iThreadContext->iError == KErrNone) &&
   499 		(iThreadContext->iDrive == aDrive) &&
   442         (iThreadContext->iDrive == aDrive) &&
   500 		(bgDesc->iByteOffset == aOffset) &&
   443         (bgDesc->iByteOffset == aOffset) &&
   501 		(bgDesc->iLength == aLength))
   444         (bgDesc->iLength == aLength))
   502 		{
   445         {
   503 		// Good: We pre-read the correct data :-)
   446         // Good: We pre-read the correct data :-)
   504 		__MT_READ_PRINT(_L("Match: Using pre-read data :-) :-) :-) :-)"));
   447         OstTrace0(TRACE_SMASSSTORAGE_MEDIADB, CTHREADCONTEXT_70, "Match: Using pre-read data :-) :-) :-) :-)");
   505 		}
   448         }
   506 	else
   449     else
   507 		{
   450         {
   508 		__MT_READ_PRINT(_L("Not using pre-read data"));
   451         OstTrace0(TRACE_SMASSSTORAGE_MEDIADB, CTHREADCONTEXT_71, "Not using pre-read data");
   509 		if (iThreadContext->iError != KErrNone)
   452         if (iThreadContext->iError != KErrNone)
   510 			{
   453             {
   511 			__MT_READ_PRINT1(_L("Pre-read failed: %d"), iThreadContext->iError);
   454             OstTrace1(TRACE_SMASSSTORAGE_MEDIADB, CTHREADCONTEXT_72, "Pre-read failed: %d", iThreadContext->iError);
   512 			}
   455             }
   513 		if (iThreadContext->iDrive != aDrive)
   456         if (iThreadContext->iDrive != aDrive)
   514 			{
   457             {
   515 			__MT_READ_PRINT2(_L("Pre-read drive mismatch: pre 0x%08x / act 0x%08x"),
   458             OstTraceExt2(TRACE_SMASSSTORAGE_MEDIADB, CTHREADCONTEXT_73,
   516 							 iThreadContext->iDrive, aDrive);
   459                          "Pre-read drive mismatch: pre 0x%08x / act 0x%08x",
   517 			}
   460                          (TUint32)iThreadContext->iDrive, (TUint32)aDrive);
   518 		if (desc->iByteOffset != aOffset)
   461             }
   519 			{
   462         if (desc->iByteOffset != aOffset)
   520 			__MT_READ_PRINT2(_L("Pre-read offset mismatch: pre %ld / act %ld"),
   463             {
   521 							 desc->iByteOffset, aOffset);
   464             OstTraceExt4(TRACE_SMASSSTORAGE_MEDIADB, CTHREADCONTEXT_74,
   522 			}
   465                          "Pre-read offset mismatch: pre 0x%x 0x%x  / act 0x%x 0x%x",
   523 		if (desc->iLength != aLength)
   466                          I64HIGH(desc->iByteOffset), I64LOW(desc->iByteOffset), I64HIGH(aOffset), I64LOW(aOffset));
   524 			{
   467             }
   525 			__MT_READ_PRINT2(_L("Pre-read length mismatch: pre %d / act %d"),
   468         if (desc->iLength != aLength)
   526 							 desc->iLength, aLength);
   469             {
   527 			// Potential optimization: If the pre-read was OK but for more data
   470             OstTraceExt2(TRACE_SMASSSTORAGE_MEDIADB, CTHREADCONTEXT_75,
   528 			// than the host is now asking for, we could still satisfy that
   471                          "Pre-read length mismatch: pre 0x%x / act 0x%x",
   529 			// request from the pre-read data by shortening the buffer.
   472                          (TUint32)desc->iLength, aLength);
   530 			}
   473             // Potential optimization: If the pre-read was OK but for more data
   531 		// No valid pre-read data was available - so we have to read it now
   474             // than the host is now asking for, we could still satisfy that
   532 		bgDesc->iByteOffset = aOffset;
   475             // request from the pre-read data by shortening the buffer.
   533 		bgDesc->iLength = aLength;
   476             }
   534 		TInt err = aDrive->Read(aOffset,
   477         // No valid pre-read data was available - so we have to read it now
   535 								aLength,
   478         bgDesc->iByteOffset = aOffset;
   536 								bgDesc->iBuf,
   479         bgDesc->iLength = aLength;
   537 								aDrive->IsWholeMediaAccess());
   480         TInt err = aDrive->Read(aOffset,
   538 		if (err != KErrNone)
   481                                 aLength,
   539 			{
   482                                 bgDesc->iBuf,
   540 			__PRINT1(_L("Read failed, err=%d\n"), err);
   483                                 aDrive->IsWholeMediaAccess());
   541 			// +++ READ CS ENDS HERE +++
   484         if (err != KErrNone)
   542 			__PRINT(_L("Signalling Read CS..."));
   485             {
   543 			iThreadContext->iCritSect.Signal();
   486             OstTrace1(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_76, "Read failed, err=%d", err);
   544 			return EFalse;
   487             // +++ READ CS ENDS HERE +++
   545 			}
   488             OstTrace0(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_77, "Signalling Read CS...");
   546 		}
   489             iThreadContext->iCritSect.Signal();
   547 
   490             return EFalse;
   548 	// Prepare thread variables for next pre-read attempt by the ReadThread
   491             }
   549 	const TInt64 offs_new = aOffset + aLength;
   492         }
   550 	iThreadContext->iDrive = aDrive;	// same drive
   493 
   551 	desc->iByteOffset = offs_new;		// next block
   494     // Prepare thread variables for next pre-read attempt by the ReadThread
   552 	desc->iLength = aLength;			// same length
   495     const TInt64 offs_new = aOffset + aLength;
   553 	iCompleted = EFalse;
   496     iThreadContext->iDrive = aDrive;    // same drive
   554 	iThreadContext->iBuffer.SwapDesc();
   497     desc->iByteOffset = offs_new;       // next block
   555 
   498     desc->iLength = aLength;            // same length
   556 	// +++ READ CS ENDS HERE +++
   499     iCompleted = EFalse;
   557 	__PRINT(_L("Signalling Read CS..."));
   500     iThreadContext->iBuffer.SwapDesc();
   558 	iThreadContext->iCritSect.Signal();
   501 
   559 	// Start background read
   502     // +++ READ CS ENDS HERE +++
   560 	__PRINT(_L("Resuming Read Thread"));
   503     OstTrace0(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_78, "Signalling Read CS...");
   561 	iThreadContext->Resume();
   504     iThreadContext->iCritSect.Signal();
   562 	return ETrue;
   505     // Start background read
   563 	}
   506     OstTrace0(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_79, "Resuming Read Thread");
   564 
   507     iThreadContext->Resume();
   565 /**
   508     return ETrue;
   566 Discard the read buffer. This is used to force a cache miss when reading from
   509     }
   567 the same sectors that were just written.
   510 
   568 */
       
   569 void CReadDriveThread::DiscardRead()
       
   570 {
       
   571 	__PRINT(_L("Waiting on Read CS in DiscardRead..."));
       
   572 	iThreadContext->iCritSect.Wait();
       
   573 	// +++ READ CS STARTS HERE +++
       
   574 	__PRINT(_L("Discarding pre-read buffer"));
       
   575 	iCompleted = EFalse;
       
   576 	iThreadContext->iBuffer.iDescReadPtr->iLength = 0;
       
   577 
       
   578 	// +++ READ CS ENDS HERE +++
       
   579 	__PRINT(_L("Signalling Read CS in DiscardRead..."));
       
   580 	iThreadContext->iCritSect.Signal();
       
   581 }
       
   582 #endif // MSDC_MULTITHREADED
   511 #endif // MSDC_MULTITHREADED
   583 
   512