1 // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). |
1 // Copyright (c) 2008-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". |
24 #include "msdebug.h" |
24 #include "msdebug.h" |
25 #include "msctypes.h" |
25 #include "msctypes.h" |
26 #include "shared.h" |
26 #include "shared.h" |
27 #include "msgservice.h" |
27 #include "msgservice.h" |
28 |
28 |
29 #include "mscutils.h" |
|
30 |
|
31 #include "mtransport.h" |
29 #include "mtransport.h" |
32 #include "mprotocol.h" |
30 #include "mprotocol.h" |
33 #include "tscsiclientreq.h" |
31 #include "tscsiclientreq.h" |
34 #include "tscsiprimarycmds.h" |
32 #include "tscsiprimarycmds.h" |
35 #include "tscsiblockcmds.h" |
33 #include "tscsiblockcmds.h" |
43 #include "cscsiprotocol.h" |
41 #include "cscsiprotocol.h" |
44 |
42 |
45 #include "usbmshostpanic.h" |
43 #include "usbmshostpanic.h" |
46 |
44 |
47 |
45 |
48 |
|
49 /** |
46 /** |
50 Create the CScsiProtocol object. |
47 Create the CScsiProtocol object. |
51 |
48 |
52 @param aLun The LUN for the device represented by this object |
49 @param aLun The LUN for the device represented by this object |
53 @param aTransport The transport interface |
50 @param aTransport The transport interface |
66 } |
63 } |
67 |
64 |
68 void CScsiProtocol::ConstructL(TLun aLun) |
65 void CScsiProtocol::ConstructL(TLun aLun) |
69 { |
66 { |
70 __MSFNLOG |
67 __MSFNLOG |
|
68 // iState = EEntry; |
71 iFsm = CMassStorageFsm::NewL(*this); |
69 iFsm = CMassStorageFsm::NewL(*this); |
72 iState = EDisconnected; |
|
73 |
70 |
74 const TInt blockLength = 0x200; |
71 const TInt blockLength = 0x200; |
75 |
72 |
76 iHeadbuf.CreateL(blockLength); |
73 iHeadbuf.CreateL(blockLength); |
77 iTailbuf.CreateL(blockLength); |
74 iTailbuf.CreateL(blockLength); |
97 |
94 |
98 |
95 |
99 void CScsiProtocol::InitialiseUnitL() |
96 void CScsiProtocol::InitialiseUnitL() |
100 { |
97 { |
101 __MSFNLOG |
98 __MSFNLOG |
|
99 iState = EDisconnected; |
102 |
100 |
103 // A device may take time to mount the media. If the device fails attempt to |
101 // A device may take time to mount the media. If the device fails attempt to |
104 // retry the connection for a number of seconds |
102 // retry the connection for a number of seconds |
105 TInt retryCounter = 20; |
103 TInt retryCounter = 20; |
106 do |
104 do |
107 { |
105 { |
108 retryCounter--; |
106 retryCounter--; |
109 iFsm->ConnectLogicalUnitL(); |
107 TInt err = iFsm->ConnectLogicalUnitL(); |
110 iState = iFsm->IsConnected() ? EConnected: EDisconnected; |
108 if (err == KErrNotSupported) |
111 |
|
112 if (iState == EConnected) |
|
113 { |
109 { |
114 break; |
110 break; |
115 } |
111 } |
|
112 if (iFsm->IsConnected()) |
|
113 { |
|
114 iState = EConnected; |
|
115 break; |
|
116 } |
116 User::After(1000 * 200); // 200 mS |
117 User::After(1000 * 200); // 200 mS |
117 } |
118 } |
118 while (retryCounter); |
119 while (retryCounter); |
119 } |
120 } |
120 |
121 |
134 void CScsiProtocol::ReadL(TPos aPos, |
135 void CScsiProtocol::ReadL(TPos aPos, |
135 TDes8& aBuf, |
136 TDes8& aBuf, |
136 TInt aLength) |
137 TInt aLength) |
137 { |
138 { |
138 __MSFNLOG |
139 __MSFNLOG |
|
140 |
|
141 if (!iSbcInterface) |
|
142 User::Leave(KErrNotSupported); |
|
143 |
139 if(!IsConnected()) |
144 if(!IsConnected()) |
140 User::Leave(KErrNotReady); |
145 User::Leave(KErrNotReady); |
141 iSbcInterface->iBlockTransfer.ReadL(*this, aPos, aLength, aBuf); |
146 iSbcInterface->iBlockTransfer.ReadL(*this, aPos, aLength, aBuf); |
142 } |
147 } |
143 |
148 |
144 |
149 |
145 void CScsiProtocol::BlockReadL(TPos aPos, TDes8& aCopybuf, TInt aLen) |
150 void CScsiProtocol::BlockReadL(TPos aPos, TDes8& aCopybuf, TInt aLen) |
146 { |
151 { |
147 __MSFNLOG |
152 __MSFNLOG |
|
153 if (!iSbcInterface) |
|
154 User::Leave(KErrNotSupported); |
|
155 |
148 __ASSERT_DEBUG(aPos % iSbcInterface->iBlockTransfer.BlockLength() == 0, |
156 __ASSERT_DEBUG(aPos % iSbcInterface->iBlockTransfer.BlockLength() == 0, |
149 User::Panic(KUsbMsHostPanicCat, EBlockDevice)); |
157 User::Panic(KUsbMsHostPanicCat, EBlockDevice)); |
150 |
158 |
151 const TInt blockLen = iSbcInterface->iBlockTransfer.BlockLength(); |
159 const TInt blockLen = iSbcInterface->iBlockTransfer.BlockLength(); |
152 TInt len = aLen; |
160 TInt len = aLen; |
187 |
194 |
188 // read rest of the block |
195 // read rest of the block |
189 TInt err = iSbcInterface->Read10L(aPos/blockLen, aCopybuf, len); |
196 TInt err = iSbcInterface->Read10L(aPos/blockLen, aCopybuf, len); |
190 if (err) |
197 if (err) |
191 { |
198 { |
192 DoCheckConditionL(); |
199 User::LeaveIfError(DoCheckConditionL()); |
193 User::LeaveIfError(KErrAbort); |
|
194 } |
200 } |
195 } |
201 } |
196 } |
202 } |
197 |
203 |
198 |
204 |
199 void CScsiProtocol::WriteL(TPos aPosition, |
205 void CScsiProtocol::WriteL(TPos aPosition, |
200 TDesC8& aBuf, |
206 TDesC8& aBuf, |
201 TInt aLength) |
207 TInt aLength) |
202 { |
208 { |
203 __MSFNLOG |
209 __MSFNLOG |
|
210 if (!iSbcInterface) |
|
211 User::Leave(KErrNotSupported); |
|
212 |
204 if(!IsConnected()) |
213 if(!IsConnected()) |
205 User::Leave(KErrNotReady); |
214 User::Leave(KErrNotReady); |
206 iSbcInterface->iBlockTransfer.WriteL(*this, aPosition, aLength, aBuf); |
215 iSbcInterface->iBlockTransfer.WriteL(*this, aPosition, aLength, aBuf); |
207 } |
216 } |
208 |
217 |
209 |
218 |
210 void CScsiProtocol::BlockWriteL(TPos aPos, TDesC8& aCopybuf, TUint aOffset, TInt aLen) |
219 void CScsiProtocol::BlockWriteL(TPos aPos, TDesC8& aCopybuf, TUint aOffset, TInt aLen) |
211 { |
220 { |
212 __MSFNLOG |
221 __MSFNLOG |
|
222 if (!iSbcInterface) |
|
223 User::Leave(KErrNotSupported); |
|
224 |
213 __ASSERT_DEBUG(aPos % iSbcInterface->iBlockTransfer.BlockLength() == 0, |
225 __ASSERT_DEBUG(aPos % iSbcInterface->iBlockTransfer.BlockLength() == 0, |
214 User::Panic(KUsbMsHostPanicCat, EBlockDevice)); |
226 User::Panic(KUsbMsHostPanicCat, EBlockDevice)); |
215 const TInt blockLen = iSbcInterface->iBlockTransfer.BlockLength(); |
227 const TInt blockLen = iSbcInterface->iBlockTransfer.BlockLength(); |
216 TInt len = aLen; |
228 TInt len = aLen; |
217 TInt err = iSbcInterface->Write10L(aPos/blockLen, aCopybuf, aOffset, len); |
229 TInt err = iSbcInterface->Write10L(aPos/blockLen, aCopybuf, aOffset, len); |
218 if (err) |
230 if (err) |
219 { |
231 { |
220 DoCheckConditionL(); |
232 User::LeaveIfError(DoCheckConditionL()); |
221 User::LeaveIfError(KErrAbort); |
|
222 } |
233 } |
223 |
234 |
224 while (len != aLen) |
235 while (len != aLen) |
225 { |
236 { |
226 // handle residue |
237 // handle residue |
266 do |
287 do |
267 { |
288 { |
268 err = iSbcInterface->ReadCapacity10L(lastLba, blockLength); |
289 err = iSbcInterface->ReadCapacity10L(lastLba, blockLength); |
269 } while (err == KErrCommandStalled && stallCounter-- > 0); |
290 } while (err == KErrCommandStalled && stallCounter-- > 0); |
270 |
291 |
271 |
292 if (err) |
|
293 { |
|
294 // DoCheckConditionL clears sense error |
|
295 // Media not present will return KErrNotReady so leave here |
|
296 User::LeaveIfError(DoCheckConditionL()); |
|
297 } |
|
298 |
|
299 // update iWriteProtect |
|
300 err = MsModeSense10L(); |
272 if (err) |
301 if (err) |
273 { |
302 { |
274 if (err == KErrCommandFailed) |
303 if (err == KErrCommandFailed) |
275 { |
304 { |
276 // Clear sense error |
305 // Clear sense error |
277 DoCheckConditionL(); |
306 err = DoCheckConditionL(); |
278 } |
307 // ignore error if unsupported |
279 User::LeaveIfError(KErrAbort); |
308 if (err != KErrUnknown) |
280 } |
309 { |
281 |
310 User::LeaveIfError(err); |
282 // update iWriteProtect |
311 } |
283 err = MsModeSense10L(); |
|
284 if (err) |
|
285 { |
|
286 if (err == KErrCommandFailed) |
|
287 { |
|
288 // Clear sense error |
|
289 DoCheckConditionL(); |
|
290 } |
312 } |
291 |
313 |
292 err = MsModeSense6L(); |
314 err = MsModeSense6L(); |
293 if (err == KErrCommandFailed) |
315 if (err == KErrCommandFailed) |
294 { |
316 { |
295 // Clear sense error |
317 // Clear sense error |
296 DoCheckConditionL(); |
318 err = DoCheckConditionL(); |
|
319 // ignore error if unsupported |
|
320 if (err != KErrUnknown) |
|
321 { |
|
322 User::LeaveIfError(err); |
|
323 } |
297 } |
324 } |
298 } |
325 } |
299 |
326 |
300 aCapsInfo.iNumberOfBlocks = lastLba + 1; |
327 aCapsInfo.iNumberOfBlocks = lastLba + 1; |
301 aCapsInfo.iBlockLength = blockLength; |
328 aCapsInfo.iBlockLength = blockLength; |
350 &info.iIdentification.iProductId, |
377 &info.iIdentification.iProductId, |
351 &info.iIdentification.iProductRev); |
378 &info.iIdentification.iProductRev); |
352 |
379 |
353 if (info.iPeripheralQualifier != 0 && info.iPeripheralQualifier != 1) |
380 if (info.iPeripheralQualifier != 0 && info.iPeripheralQualifier != 1) |
354 { |
381 { |
355 __HOSTPRINT(_L("Peripheral Qualifier[Unknown device type]\n")) |
382 __HOSTPRINT(_L("Peripheral Qualifier[Unknown device type]")) |
356 return KErrUnknown; |
383 err = KErrUnknown; |
357 } |
384 } |
358 |
385 else if (info.iPeripheralDeviceType == 0) |
359 if (info.iPeripheralDeviceType != 0) |
386 { |
360 { |
387 // SCSI SBC Direct access device |
361 __HOSTPRINT(_L("Peripheral Device Type[Unsupported device type]\n")) |
388 iRemovableMedia = info.iRemovable; |
362 return KErrUnknown; |
389 |
363 } |
390 // SCSI Block device |
364 |
391 iSbcInterface = new (ELeave) TSbcClientInterface(iSpcInterface.Transport()); |
365 iRemovableMedia = info.iRemovable; |
392 iSbcInterface->InitBuffers(&iHeadbuf, &iTailbuf); |
366 |
393 err = KErrNone; |
367 // SCSI Block device |
394 } |
368 iSbcInterface = new (ELeave) TSbcClientInterface(iSpcInterface.Transport()); |
395 else if (info.iPeripheralDeviceType == 5) |
369 iSbcInterface->InitBuffers(&iHeadbuf, &iTailbuf); |
396 { |
370 |
397 // SCSI MMC-2 CD-ROM device |
371 return KErrNone; |
398 __HOSTPRINT(_L("Peripheral Device Type[CD-ROM]")) |
|
399 iRemovableMedia = info.iRemovable; |
|
400 |
|
401 // MMC-2 is not supported. A SCSI interface call will return |
|
402 // KErrNotSupported. If SCSI support is extended in future then |
|
403 // TSbcInterface class should be replaced with a proper interface class. |
|
404 iSbcInterface = NULL; |
|
405 err = KErrNone; |
|
406 } |
|
407 else |
|
408 { |
|
409 __HOSTPRINT(_L("Peripheral Device Type[Unsupported device type]")) |
|
410 err = KErrUnknown; |
|
411 } |
|
412 |
|
413 return err; |
372 } |
414 } |
373 |
415 |
374 |
416 |
375 /** |
417 /** |
376 Perform SCSI TEST UNIT READY command. The function leaves if the device response |
418 Perform SCSI TEST UNIT READY command. The function leaves if the device response |
419 device status error, KErrCommandStalled to indicate a device stall |
466 device status error, KErrCommandStalled to indicate a device stall |
420 */ |
467 */ |
421 TInt CScsiProtocol::MsModeSense10L() |
468 TInt CScsiProtocol::MsModeSense10L() |
422 { |
469 { |
423 __MSFNLOG |
470 __MSFNLOG |
|
471 if (!iSbcInterface) |
|
472 User::Leave(KErrNotSupported); |
|
473 |
424 TBool writeProtected; |
474 TBool writeProtected; |
425 TInt err = iSbcInterface->ModeSense10L(TSbcClientInterface::EReturnAllModePages, writeProtected); |
475 TInt err = iSbcInterface->ModeSense10L(TSbcClientInterface::EReturnAllModePages, writeProtected); |
426 |
476 |
427 if (!err) |
477 if (!err) |
428 { |
478 { |
440 device status error, KErrCommandStalled to indicate a device stall |
490 device status error, KErrCommandStalled to indicate a device stall |
441 */ |
491 */ |
442 TInt CScsiProtocol::MsModeSense6L() |
492 TInt CScsiProtocol::MsModeSense6L() |
443 { |
493 { |
444 __MSFNLOG |
494 __MSFNLOG |
|
495 if (!iSbcInterface) |
|
496 User::Leave(KErrNotSupported); |
|
497 |
445 TBool writeProtected; |
498 TBool writeProtected; |
446 TInt err = iSbcInterface->ModeSense6L(TSbcClientInterface::EReturnAllModePages, writeProtected); |
499 TInt err = iSbcInterface->ModeSense6L(TSbcClientInterface::EReturnAllModePages, writeProtected); |
447 |
500 |
448 if (!err) |
501 if (!err) |
449 { |
502 { |
479 __MSFNLOG |
535 __MSFNLOG |
480 return iSpcInterface.PreventAllowMediumRemovalL(aPrevent); |
536 return iSpcInterface.PreventAllowMediumRemovalL(aPrevent); |
481 } |
537 } |
482 |
538 |
483 |
539 |
484 void CScsiProtocol::DoCheckConditionL() |
540 TInt CScsiProtocol::DoCheckConditionL() |
485 { |
541 { |
486 __MSFNLOG |
542 __MSFNLOG |
487 User::LeaveIfError(MsRequestSenseL()); |
543 User::LeaveIfError(MsRequestSenseL()); |
|
544 |
|
545 TInt err; |
488 |
546 |
489 // Check if init is needed |
547 // Check if init is needed |
490 if (iSenseInfo.iSenseCode == TSenseInfo::ENotReady && |
548 if (iSenseInfo.iSenseCode == TSenseInfo::ENotReady && |
491 iSenseInfo.iAdditional == TSenseInfo::EAscLogicalUnitNotReady && |
549 iSenseInfo.iAdditional == TSenseInfo::EAscLogicalUnitNotReady && |
492 iSenseInfo.iQualifier == TSenseInfo::EAscqInitializingCommandRequired) |
550 iSenseInfo.iQualifier == TSenseInfo::EAscqInitializingCommandRequired) |
493 { |
551 { |
494 // start unit |
552 if (iSbcInterface) |
495 TInt err = iSbcInterface->StartStopUnitL(ETrue); |
553 { |
496 |
554 // start unit |
497 if (err) |
555 err = iSbcInterface->StartStopUnitL(ETrue); |
498 { |
556 if (err) |
499 User::LeaveIfError(MsRequestSenseL()); |
557 { |
500 } |
558 User::LeaveIfError(MsRequestSenseL()); |
501 |
559 } |
502 } |
560 } |
503 |
561 } |
504 TInt r = GetSystemWideSenseError(iSenseInfo); |
562 |
505 |
563 err = GetSystemWideSenseError(iSenseInfo); |
506 if (((r == KErrNotReady) && (iState == EConnected)) || |
564 |
507 r == KErrDisconnected) |
565 TScsiState nextState = iState; |
508 { |
566 if (err == KErrDisconnected) |
509 CompleteNotifyChangeL(); |
567 { |
510 } |
568 nextState = EDisconnected; |
|
569 } |
|
570 else if (err == KErrNotReady) |
|
571 { |
|
572 nextState = EMediaNotPresent; |
|
573 } |
|
574 else |
|
575 { |
|
576 // no state change; |
|
577 } |
|
578 |
|
579 if (nextState != iState) |
|
580 { |
|
581 iMediaChangeNotifier.DoNotifyL(); |
|
582 iState = nextState; |
|
583 } |
|
584 |
|
585 return err; |
511 } |
586 } |
512 |
587 |
513 |
588 |
514 /** |
589 /** |
515 Map SCSI sense error to a system wide error code |
590 Map SCSI sense error to a system wide error code |
728 void CScsiProtocol::DoScsiReadyCheckEventL() |
803 void CScsiProtocol::DoScsiReadyCheckEventL() |
729 { |
804 { |
730 __MSFNLOG |
805 __MSFNLOG |
731 TInt err = KErrNone; |
806 TInt err = KErrNone; |
732 |
807 |
733 if(iFsm->IsRemovableMedia() || iState == EDisconnected) |
808 if(iRemovableMedia || iState != EConnected) |
734 { |
809 { |
735 iFsm->SetStatusCheck(); |
810 iFsm->SetStatusCheck(); |
736 TRAP(err, iFsm->ConnectLogicalUnitL()); |
811 TRAP(err, iFsm->ConnectLogicalUnitL()); |
737 iFsm->ClearStatusCheck(); |
812 iFsm->ClearStatusCheck(); |
738 |
813 |
758 iMediaChangeNotifier.DoNotifyL(); |
833 iMediaChangeNotifier.DoNotifyL(); |
759 } |
834 } |
760 } |
835 } |
761 } |
836 } |
762 |
837 |
763 void CScsiProtocol::CompleteNotifyChangeL() |
|
764 { |
|
765 __MSFNLOG |
|
766 if (!iFsm->IsStatusCheck()) |
|
767 { |
|
768 if (iState == EConnected) |
|
769 { |
|
770 iState = EDisconnected; |
|
771 iMediaChangeNotifier.DoNotifyL(); |
|
772 } |
|
773 } |
|
774 } |
|
775 |
838 |
776 RMediaChangeNotifier::RMediaChangeNotifier() |
839 RMediaChangeNotifier::RMediaChangeNotifier() |
777 : iRegistered(EFalse) |
840 : iRegistered(EFalse) |
778 { |
841 { |
779 __MSFNSLOG |
842 __MSFNSLOG |