Add MMC/SD command to send SET_BLOCK_COUNT, READ_MULTIPLE_BLOCK and STOP_TRANSMISSION in a single call.

This commit is contained in:
2020-12-12 21:03:44 +00:00
parent 5e39e581ef
commit a026b525a2
3 changed files with 205 additions and 35 deletions

View File

@@ -42,7 +42,9 @@ using Aaru.CommonTypes.Interfaces;
using Aaru.CommonTypes.Metadata;
using Aaru.Core.Logging;
using Aaru.Decoders.MMC;
using Aaru.Decoders.SecureDigital;
using Schemas;
using CSD = Aaru.Decoders.MMC.CSD;
using DeviceType = Aaru.CommonTypes.Enums.DeviceType;
using MediaType = Aaru.CommonTypes.MediaType;
using Version = Aaru.CommonTypes.Interop.Version;
@@ -85,6 +87,7 @@ namespace Aaru.Core.Devices.Dumping
uint physicalBlockSize = 0;
bool byteAddressed = true;
uint[] response;
bool supportsCmd23 = false;
Dictionary<MediaTagType, byte[]> mediaTags = new Dictionary<MediaTagType, byte[]>();
@@ -104,6 +107,9 @@ namespace Aaru.Core.Devices.Dumping
mediaTags.Add(MediaTagType.MMC_CSD, null);
// Found at least since MMC System Specification 3.31
supportsCmd23 = csdDecoded.Version >= 3;
if(csdDecoded.Size == 0xFFF)
{
UpdateStatus?.Invoke("Reading Extended CSD");
@@ -215,7 +221,12 @@ namespace Aaru.Core.Devices.Dumping
scr = null;
}
else
{
supportsCmd23 = Decoders.SecureDigital.Decoders.DecodeSCR(scr)?.CommandSupport.
HasFlag(CommandSupport.SetBlockCount) ?? false;
mediaTags.Add(MediaTagType.SD_SCR, null);
}
break;
}
@@ -254,9 +265,39 @@ namespace Aaru.Core.Devices.Dumping
byte[] cmdBuf;
bool error;
if(blocksToRead > _maximumReadable)
blocksToRead = (ushort)_maximumReadable;
if(supportsCmd23 && blocksToRead > 1)
{
sense = _dev.ReadWithBlockCount(out cmdBuf, out _, 0, blockSize, 1, byteAddressed, timeout,
out duration);
if(sense || _dev.Error)
{
UpdateStatus?.
Invoke("Environment does not support setting block count, downgrading to OS reading.");
supportsCmd23 = false;
}
// Need to restart device, otherwise is it just busy streaming data with no one listening
sense = _dev.ReOpen();
if(sense)
{
StoppingErrorMessage?.Invoke($"Error {_dev.LastError} reopening device.");
return;
}
}
if(supportsCmd23 && blocksToRead > 1)
{
while(true)
{
error = _dev.Read(out cmdBuf, out _, 0, blockSize, blocksToRead, byteAddressed, timeout, out duration);
error = _dev.ReadWithBlockCount(out cmdBuf, out _, 0, blockSize, blocksToRead, byteAddressed,
timeout, out duration);
if(error)
blocksToRead /= 2;
@@ -269,13 +310,24 @@ namespace Aaru.Core.Devices.Dumping
if(error)
{
_dumpLog.WriteLine("ERROR: Cannot get blocks to read, device error {0}.", _dev.LastError);
StoppingErrorMessage?.Invoke($"Device error {_dev.LastError} trying to guess ideal transfer length.");
StoppingErrorMessage?.
Invoke($"Device error {_dev.LastError} trying to guess ideal transfer length.");
return;
}
}
if(supportsCmd23 || blocksToRead == 1)
{
UpdateStatus?.Invoke($"Device can read {blocksToRead} blocks at a time.");
_dumpLog.WriteLine("Device can read {0} blocks at a time.", blocksToRead);
}
else
{
UpdateStatus?.Invoke($"Device can read {blocksToRead} blocks using sequential commands.");
_dumpLog.WriteLine("Device can read {0} blocks using sequential commands.", blocksToRead);
}
if(_skip < blocksToRead)
_skip = blocksToRead;
@@ -491,8 +543,15 @@ namespace Aaru.Core.Devices.Dumping
UpdateProgress?.Invoke($"Reading sector {i} of {blocks} ({currentSpeed:F3} MiB/sec.)", (long)i,
(long)blocks);
error = _dev.Read(out cmdBuf, out response, (uint)i, blockSize, blocksToRead, byteAddressed, timeout,
if(blocksToRead == 1)
error = _dev.ReadSingleBlock(out cmdBuf, out _, (uint)i, blockSize, byteAddressed, timeout,
out duration);
else if(supportsCmd23)
error = _dev.ReadWithBlockCount(out cmdBuf, out _, (uint)i, blockSize, blocksToRead, byteAddressed,
timeout, out duration);
else
error = _dev.ReadMultipleUsingSingle(out cmdBuf, out _, (uint)i, blockSize, blocksToRead,
byteAddressed, timeout, out duration);
if(!error)
{
@@ -588,8 +647,8 @@ namespace Aaru.Core.Devices.Dumping
PulseProgress?.Invoke($"Trimming sector {badSector}");
error = _dev.Read(out cmdBuf, out response, (uint)badSector, blockSize, 1, byteAddressed, timeout,
out duration);
error = _dev.ReadSingleBlock(out cmdBuf, out response, (uint)badSector, blockSize, byteAddressed,
timeout, out duration);
totalDuration += duration;
@@ -640,8 +699,8 @@ namespace Aaru.Core.Devices.Dumping
forward ? "forward" : "reverse",
runningPersistent ? "recovering partial data, " : ""));
error = _dev.Read(out cmdBuf, out response, (uint)badSector, blockSize, 1, byteAddressed, timeout,
out duration);
error = _dev.ReadSingleBlock(out cmdBuf, out response, (uint)badSector, blockSize, byteAddressed,
timeout, out duration);
totalDuration += duration;

View File

@@ -34,6 +34,8 @@ using System;
using System.Collections.Generic;
using Aaru.Core.Logging;
using Aaru.Decoders.MMC;
using Aaru.Decoders.SecureDigital;
using CSD = Aaru.Decoders.MMC.CSD;
using DeviceType = Aaru.CommonTypes.Enums.DeviceType;
// ReSharper disable JoinDeclarationAndInitializer
@@ -55,6 +57,7 @@ namespace Aaru.Core.Devices.Scanning
ushort blocksToRead = 128;
uint blockSize = 512;
bool byteAddressed = true;
bool supportsCmd23 = false;
switch(_dev.Type)
{
@@ -68,6 +71,9 @@ namespace Aaru.Core.Devices.Scanning
results.Blocks = (ulong)((csd.Size + 1) * Math.Pow(2, csd.SizeMultiplier + 2));
blockSize = (uint)Math.Pow(2, csd.ReadBlockLength);
// Found at least since MMC System Specification 3.31
supportsCmd23 = csd.Version >= 3;
if(csd.Size == 0xFFF)
{
sense = _dev.ReadExtendedCsd(out cmdBuf, out _, timeout, out _);
@@ -115,6 +121,12 @@ namespace Aaru.Core.Devices.Scanning
results.Blocks *= ratio;
blockSize = 512;
}
sense = _dev.ReadScr(out cmdBuf, out _, timeout, out _);
if(!sense)
supportsCmd23 = Decoders.SecureDigital.Decoders.DecodeSCR(cmdBuf)?.CommandSupport.
HasFlag(CommandSupport.SetBlockCount) ?? false;
}
break;
@@ -128,9 +140,36 @@ namespace Aaru.Core.Devices.Scanning
return results;
}
if(supportsCmd23)
{
sense = _dev.ReadWithBlockCount(out cmdBuf, out _, 0, blockSize, 1, byteAddressed, timeout,
out duration);
if(sense || _dev.Error)
{
UpdateStatus?.
Invoke("Environment does not support setting block count, downgrading to OS reading.");
supportsCmd23 = false;
}
// Need to restart device, otherwise is it just busy streaming data with no one listening
sense = _dev.ReOpen();
if(sense)
{
StoppingErrorMessage?.Invoke($"Error {_dev.LastError} reopening device.");
return results;
}
}
if(supportsCmd23)
{
while(true)
{
sense = _dev.Read(out cmdBuf, out _, 0, blockSize, blocksToRead, byteAddressed, timeout, out duration);
sense = _dev.ReadWithBlockCount(out cmdBuf, out _, 0, blockSize, blocksToRead, byteAddressed,
timeout, out duration);
if(sense)
blocksToRead /= 2;
@@ -142,10 +181,12 @@ namespace Aaru.Core.Devices.Scanning
if(sense)
{
StoppingErrorMessage?.Invoke($"Device error {_dev.LastError} trying to guess ideal transfer length.");
StoppingErrorMessage?.
Invoke($"Device error {_dev.LastError} trying to guess ideal transfer length.");
return results;
}
}
results.A = 0; // <3ms
results.B = 0; // >=3ms, <10ms
@@ -164,11 +205,14 @@ namespace Aaru.Core.Devices.Scanning
results.SeekMax = double.MinValue;
results.SeekMin = double.MaxValue;
results.SeekTotal = 0;
const int SEEK_TIMES = 100;
const int seekTimes = 100;
var rnd = new Random();
if(supportsCmd23 || blocksToRead == 1)
UpdateStatus?.Invoke($"Reading {blocksToRead} sectors at a time.");
else
UpdateStatus?.Invoke($"Reading {blocksToRead} sectors using sequential single commands.");
InitBlockMap?.Invoke(results.Blocks, blockSize, blocksToRead, sdProfile);
var mhddLog = new MhddLog(_mhddLogPath, _dev, results.Blocks, blockSize, blocksToRead, false);
@@ -198,8 +242,17 @@ namespace Aaru.Core.Devices.Scanning
UpdateProgress?.Invoke($"Reading sector {i} of {results.Blocks} ({currentSpeed:F3} MiB/sec.)", (long)i,
(long)results.Blocks);
bool error = _dev.Read(out cmdBuf, out _, (uint)i, blockSize, blocksToRead, byteAddressed, timeout,
bool error;
if(blocksToRead == 1)
error = _dev.ReadSingleBlock(out cmdBuf, out _, (uint)i, blockSize, byteAddressed, timeout,
out duration);
else if(supportsCmd23)
error = _dev.ReadWithBlockCount(out cmdBuf, out _, (uint)i, blockSize, blocksToRead, byteAddressed,
timeout, out duration);
else
error = _dev.ReadMultipleUsingSingle(out cmdBuf, out _, (uint)i, blockSize, blocksToRead,
byteAddressed, timeout, out duration);
if(!error)
{
@@ -256,7 +309,7 @@ namespace Aaru.Core.Devices.Scanning
InitProgress?.Invoke();
for(int i = 0; i < SEEK_TIMES; i++)
for(int i = 0; i < seekTimes; i++)
{
if(_aborted || !_seekTest)
break;
@@ -285,7 +338,7 @@ namespace Aaru.Core.Devices.Scanning
results.ProcessingTime /= 1000;
results.TotalTime = (end - start).TotalSeconds;
results.AvgSpeed = blockSize * (double)(results.Blocks + 1) / 1048576 / results.ProcessingTime;
results.SeekTimes = SEEK_TIMES;
results.SeekTimes = seekTimes;
return results;
}

View File

@@ -243,5 +243,63 @@ namespace Aaru.Devices
return sense;
}
public bool ReadWithBlockCount(out byte[] buffer, out uint[] response, uint lba, uint blockSize,
ushort transferLength, bool byteAddressed, uint timeout, out double duration)
{
uint address = byteAddressed ? lba * blockSize : lba;
MmcSingleCommand[] commands = new MmcSingleCommand[3];
// SET_BLOCK_COUNT
commands[0] = new MmcSingleCommand
{
command = MmcCommands.SetBlockCount,
write = false,
isApplication = false,
flags = MmcFlags.ResponseSpiR1 | MmcFlags.ResponseR1 | MmcFlags.CommandAc,
argument = transferLength,
blockSize = 0,
blocks = 0,
buffer = new byte[0]
};
// READ_MULTIPLE_BLOCK
commands[1] = new MmcSingleCommand
{
command = MmcCommands.ReadMultipleBlock,
write = false,
isApplication = false,
flags = MmcFlags.ResponseSpiR1 | MmcFlags.ResponseR1 | MmcFlags.CommandAdtc,
argument = address,
blockSize = blockSize,
blocks = transferLength,
buffer = new byte[transferLength * blockSize]
};
// STOP_TRANSMISSION
// Needed if the previous command fails
commands[2] = new MmcSingleCommand
{
command = MmcCommands.StopTransmission,
write = false,
isApplication = false,
flags = MmcFlags.ResponseSpiR1B | MmcFlags.ResponseR1B | MmcFlags.CommandAc,
argument = 0,
blockSize = 0,
blocks = 0,
buffer = new byte[0]
};
LastError = SendMultipleMmcCommands(commands, out duration, out bool sense, timeout);
Error = LastError != 0;
AaruConsole.DebugWriteLine("SecureDigital Device", "READ_MULTIPLE_BLOCK took {0} ms.", duration);
buffer = commands[1].buffer;
response = commands[1].response;
return sense;
}
}
}