mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 19:24:25 +00:00
🐛Fix sending error recovery MODE page to devices before trying damaged sectors. Fixes #169
This commit is contained in:
@@ -82,16 +82,16 @@ namespace DiscImageChef.Core.Devices.Dumping
|
|||||||
/// <exception cref="NotImplementedException">If trying to dump scrambled sectors</exception>
|
/// <exception cref="NotImplementedException">If trying to dump scrambled sectors</exception>
|
||||||
/// <exception cref="InvalidOperationException">If the resume file is invalid</exception>
|
/// <exception cref="InvalidOperationException">If the resume file is invalid</exception>
|
||||||
/// <exception cref="ArgumentOutOfRangeException">If the track type is unknown (never)</exception>
|
/// <exception cref="ArgumentOutOfRangeException">If the track type is unknown (never)</exception>
|
||||||
internal static void Dump(Device dev, string devicePath, IWritableImage outputPlugin, ushort retryPasses,
|
internal static void Dump(Device dev, string devicePath,
|
||||||
bool force, bool dumpRaw, bool persistent, bool stopOnError,
|
IWritableImage outputPlugin, ushort retryPasses,
|
||||||
ref MediaType dskType,
|
bool force, bool dumpRaw,
|
||||||
ref
|
bool persistent, bool stopOnError, ref MediaType dskType,
|
||||||
Resume resume, ref DumpLog dumpLog, bool dumpLeadIn,
|
ref Resume resume, ref DumpLog dumpLog,
|
||||||
Encoding encoding,
|
bool dumpLeadIn, Encoding encoding,
|
||||||
string
|
string outputPrefix, string outputPath,
|
||||||
outputPrefix, string outputPath, Dictionary<string, string> formatOptions,
|
Dictionary<string, string> formatOptions,
|
||||||
CICMMetadataType
|
CICMMetadataType preSidecar, uint skip,
|
||||||
preSidecar, uint skip, bool nometadata)
|
bool nometadata)
|
||||||
{
|
{
|
||||||
uint subSize;
|
uint subSize;
|
||||||
DateTime start;
|
DateTime start;
|
||||||
@@ -335,8 +335,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
|||||||
toc.Value.TrackDescriptors.OrderBy(track => track.POINT).ToArray();
|
toc.Value.TrackDescriptors.OrderBy(track => track.POINT).ToArray();
|
||||||
|
|
||||||
foreach(FullTOC.TrackDataDescriptor trk in sortedTracks.Where(trk => trk.ADR == 1 || trk.ADR == 4))
|
foreach(FullTOC.TrackDataDescriptor trk in sortedTracks.Where(trk => trk.ADR == 1 || trk.ADR == 4))
|
||||||
if(trk.POINT >= 0x01 &&
|
if(trk.POINT >= 0x01 && trk.POINT <= 0x63)
|
||||||
trk.POINT <= 0x63)
|
|
||||||
{
|
{
|
||||||
trackList.Add(new Track
|
trackList.Add(new Track
|
||||||
{
|
{
|
||||||
@@ -732,8 +731,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
|||||||
subSize = 0;
|
subSize = 0;
|
||||||
blockSize = SECTOR_SIZE + subSize;
|
blockSize = SECTOR_SIZE + subSize;
|
||||||
for(int t = 0; t < tracks.Length; t++) tracks[t].TrackSubchannelType = TrackSubchannelType.None;
|
for(int t = 0; t < tracks.Length; t++) tracks[t].TrackSubchannelType = TrackSubchannelType.None;
|
||||||
ret =
|
ret = outputPlugin.SetTracks(tracks.ToList());
|
||||||
outputPlugin.SetTracks(tracks.ToList());
|
|
||||||
if(!ret)
|
if(!ret)
|
||||||
{
|
{
|
||||||
dumpLog.WriteLine("Error sending tracks to output image, not continuing.");
|
dumpLog.WriteLine("Error sending tracks to output image, not continuing.");
|
||||||
@@ -888,10 +886,9 @@ namespace DiscImageChef.Core.Devices.Dumping
|
|||||||
end = DateTime.UtcNow;
|
end = DateTime.UtcNow;
|
||||||
mhddLog.Close();
|
mhddLog.Close();
|
||||||
ibgLog.Close(dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024,
|
ibgLog.Close(dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024,
|
||||||
blockSize * (double)(blocks + 1) /
|
blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000),
|
||||||
1024 / (totalDuration / 1000), devicePath);
|
devicePath);
|
||||||
dumpLog.WriteLine("Dump finished in {0} seconds.",
|
dumpLog.WriteLine("Dump finished in {0} seconds.", (end - start).TotalSeconds);
|
||||||
(end - start).TotalSeconds);
|
|
||||||
dumpLog.WriteLine("Average dump speed {0:F3} KiB/sec.",
|
dumpLog.WriteLine("Average dump speed {0:F3} KiB/sec.",
|
||||||
(double)blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000));
|
(double)blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000));
|
||||||
dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.",
|
dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.",
|
||||||
@@ -906,6 +903,44 @@ namespace DiscImageChef.Core.Devices.Dumping
|
|||||||
bool forward = true;
|
bool forward = true;
|
||||||
bool runningPersistent = false;
|
bool runningPersistent = false;
|
||||||
|
|
||||||
|
Modes.ModePage? currentModePage = null;
|
||||||
|
byte[] md6;
|
||||||
|
byte[] md10;
|
||||||
|
|
||||||
|
if(persistent)
|
||||||
|
{
|
||||||
|
Modes.ModePage_01_MMC pgMmc =
|
||||||
|
new Modes.ModePage_01_MMC {PS = false, ReadRetryCount = 255, Parameter = 0x20};
|
||||||
|
Modes.DecodedMode md = new Modes.DecodedMode
|
||||||
|
{
|
||||||
|
Header = new Modes.ModeHeader(),
|
||||||
|
Pages = new[]
|
||||||
|
{
|
||||||
|
new Modes.ModePage
|
||||||
|
{
|
||||||
|
Page = 0x01,
|
||||||
|
Subpage = 0x00,
|
||||||
|
PageResponse = Modes.EncodeModePage_01_MMC(pgMmc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
md6 = Modes.EncodeMode6(md, dev.ScsiType);
|
||||||
|
md10 = Modes.EncodeMode10(md, dev.ScsiType);
|
||||||
|
|
||||||
|
dumpLog.WriteLine("Sending MODE SELECT to drive.");
|
||||||
|
sense = dev.ModeSelect(md6, out senseBuf, true, false, dev.Timeout, out _);
|
||||||
|
if(sense) sense = dev.ModeSelect10(md10, out senseBuf, true, false, dev.Timeout, out _);
|
||||||
|
|
||||||
|
if(sense)
|
||||||
|
{
|
||||||
|
DicConsole
|
||||||
|
.WriteLine("Drive did not accept MODE SELECT command for persistent error reading, try another drive.");
|
||||||
|
DicConsole.DebugWriteLine("Error: {0}", Sense.PrettifySense(senseBuf));
|
||||||
|
dumpLog.WriteLine("Drive did not accept MODE SELECT command for persistent error reading, try another drive.");
|
||||||
|
}
|
||||||
|
else runningPersistent = true;
|
||||||
|
}
|
||||||
|
|
||||||
cdRepeatRetry:
|
cdRepeatRetry:
|
||||||
ulong[] tmpArray = resume.BadBlocks.ToArray();
|
ulong[] tmpArray = resume.BadBlocks.ToArray();
|
||||||
foreach(ulong badSector in tmpArray)
|
foreach(ulong badSector in tmpArray)
|
||||||
@@ -960,42 +995,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
|||||||
goto cdRepeatRetry;
|
goto cdRepeatRetry;
|
||||||
}
|
}
|
||||||
|
|
||||||
Modes.ModePage? currentModePage = null;
|
if(runningPersistent && currentModePage.HasValue)
|
||||||
byte[] md6;
|
|
||||||
byte[] md10;
|
|
||||||
|
|
||||||
if(!runningPersistent && persistent)
|
|
||||||
{
|
|
||||||
Modes.ModePage_01_MMC pgMmc =
|
|
||||||
new Modes.ModePage_01_MMC {PS = false, ReadRetryCount = 255, Parameter = 0x20};
|
|
||||||
Modes.DecodedMode md = new Modes.DecodedMode
|
|
||||||
{
|
|
||||||
Header = new Modes.ModeHeader(),
|
|
||||||
Pages = new[]
|
|
||||||
{
|
|
||||||
new Modes.ModePage
|
|
||||||
{
|
|
||||||
Page = 0x01,
|
|
||||||
Subpage = 0x00,
|
|
||||||
PageResponse = Modes.EncodeModePage_01_MMC(pgMmc)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
md6 = Modes.EncodeMode6(md, dev.ScsiType);
|
|
||||||
md10 = Modes.EncodeMode10(md, dev.ScsiType);
|
|
||||||
|
|
||||||
dumpLog.WriteLine("Sending MODE SELECT to drive.");
|
|
||||||
sense = dev.ModeSelect(md6, out senseBuf, true, false, dev.Timeout, out _);
|
|
||||||
if(sense) sense = dev.ModeSelect10(md10, out senseBuf, true, false, dev.Timeout, out _);
|
|
||||||
|
|
||||||
runningPersistent = true;
|
|
||||||
if(!sense && !dev.Error)
|
|
||||||
{
|
|
||||||
pass--;
|
|
||||||
goto cdRepeatRetry;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(runningPersistent && persistent && currentModePage.HasValue)
|
|
||||||
{
|
{
|
||||||
Modes.DecodedMode md = new Modes.DecodedMode
|
Modes.DecodedMode md = new Modes.DecodedMode
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -83,12 +83,11 @@ namespace DiscImageChef.Core.Devices.Dumping
|
|||||||
bool persistent, bool stopOnError,
|
bool persistent, bool stopOnError,
|
||||||
Dictionary<MediaTagType, byte[]> mediaTags, ref MediaType dskType,
|
Dictionary<MediaTagType, byte[]> mediaTags, ref MediaType dskType,
|
||||||
bool opticalDisc,
|
bool opticalDisc,
|
||||||
ref Resume resume,
|
ref Resume resume, ref DumpLog dumpLog,
|
||||||
ref DumpLog dumpLog, Encoding encoding, string outputPrefix,
|
Encoding encoding, string outputPrefix,
|
||||||
string outputPath,
|
string outputPath, Dictionary<string, string> formatOptions,
|
||||||
Dictionary<string, string> formatOptions,
|
CICMMetadataType preSidecar, uint skip,
|
||||||
CICMMetadataType preSidecar,
|
bool nometadata)
|
||||||
uint skip, bool nometadata)
|
|
||||||
{
|
{
|
||||||
bool sense;
|
bool sense;
|
||||||
ulong blocks;
|
ulong blocks;
|
||||||
@@ -152,12 +151,9 @@ namespace DiscImageChef.Core.Devices.Dumping
|
|||||||
{
|
{
|
||||||
mediaTags = new Dictionary<MediaTagType, byte[]>();
|
mediaTags = new Dictionary<MediaTagType, byte[]>();
|
||||||
|
|
||||||
if(dev.IsUsb && dev.UsbDescriptors != null)
|
if(dev.IsUsb && dev.UsbDescriptors != null) mediaTags.Add(MediaTagType.USB_Descriptors, null);
|
||||||
mediaTags.Add(MediaTagType.USB_Descriptors, null);
|
if(dev.Type == DeviceType.ATAPI) mediaTags.Add(MediaTagType.ATAPI_IDENTIFY, null);
|
||||||
if(dev.Type == DeviceType.ATAPI)
|
if(dev.IsPcmcia && dev.Cis != null) mediaTags.Add(MediaTagType.PCMCIA_CIS, null);
|
||||||
mediaTags.Add(MediaTagType.ATAPI_IDENTIFY, null);
|
|
||||||
if(dev.IsPcmcia && dev.Cis != null)
|
|
||||||
mediaTags.Add(MediaTagType.PCMCIA_CIS, null);
|
|
||||||
|
|
||||||
sense = dev.ScsiInquiry(out byte[] cmdBuf, out _);
|
sense = dev.ScsiInquiry(out byte[] cmdBuf, out _);
|
||||||
mediaTags.Add(MediaTagType.SCSI_INQUIRY, cmdBuf);
|
mediaTags.Add(MediaTagType.SCSI_INQUIRY, cmdBuf);
|
||||||
@@ -413,10 +409,9 @@ namespace DiscImageChef.Core.Devices.Dumping
|
|||||||
DicConsole.WriteLine();
|
DicConsole.WriteLine();
|
||||||
mhddLog.Close();
|
mhddLog.Close();
|
||||||
ibgLog.Close(dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024,
|
ibgLog.Close(dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024,
|
||||||
blockSize * (double)(blocks + 1) /
|
blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000),
|
||||||
1024 / (totalDuration / 1000), devicePath);
|
devicePath);
|
||||||
dumpLog.WriteLine("Dump finished in {0} seconds.",
|
dumpLog.WriteLine("Dump finished in {0} seconds.", (end - start).TotalSeconds);
|
||||||
(end - start).TotalSeconds);
|
|
||||||
dumpLog.WriteLine("Average dump speed {0:F3} KiB/sec.",
|
dumpLog.WriteLine("Average dump speed {0:F3} KiB/sec.",
|
||||||
(double)blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000));
|
(double)blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000));
|
||||||
dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.",
|
dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.",
|
||||||
@@ -429,49 +424,11 @@ namespace DiscImageChef.Core.Devices.Dumping
|
|||||||
bool forward = true;
|
bool forward = true;
|
||||||
bool runningPersistent = false;
|
bool runningPersistent = false;
|
||||||
|
|
||||||
repeatRetry:
|
|
||||||
ulong[] tmpArray = resume.BadBlocks.ToArray();
|
|
||||||
foreach(ulong badSector in tmpArray)
|
|
||||||
{
|
|
||||||
if(aborted)
|
|
||||||
{
|
|
||||||
currentTry.Extents = ExtentsConverter.ToMetadata(extents);
|
|
||||||
dumpLog.WriteLine("Aborted!");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
DicConsole.Write("\rRetrying sector {0}, pass {1}, {3}{2}", badSector, pass + 1,
|
|
||||||
forward ? "forward" : "reverse",
|
|
||||||
runningPersistent ? "recovering partial data, " : "");
|
|
||||||
|
|
||||||
sense = scsiReader.ReadBlock(out readBuffer, badSector, out double cmdDuration);
|
|
||||||
totalDuration += cmdDuration;
|
|
||||||
|
|
||||||
if(!sense && !dev.Error)
|
|
||||||
{
|
|
||||||
resume.BadBlocks.Remove(badSector);
|
|
||||||
extents.Add(badSector);
|
|
||||||
outputPlugin.WriteSector(readBuffer, badSector);
|
|
||||||
dumpLog.WriteLine("Correctly retried block {0} in pass {1}.", badSector, pass);
|
|
||||||
}
|
|
||||||
else if(runningPersistent)
|
|
||||||
outputPlugin.WriteSector(readBuffer, badSector);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(pass < retryPasses && !aborted && resume.BadBlocks.Count > 0)
|
|
||||||
{
|
|
||||||
pass++;
|
|
||||||
forward = !forward;
|
|
||||||
resume.BadBlocks.Sort();
|
|
||||||
resume.BadBlocks.Reverse();
|
|
||||||
goto repeatRetry;
|
|
||||||
}
|
|
||||||
|
|
||||||
Modes.ModePage? currentModePage = null;
|
Modes.ModePage? currentModePage = null;
|
||||||
byte[] md6;
|
byte[] md6;
|
||||||
byte[] md10;
|
byte[] md10;
|
||||||
|
|
||||||
if(!runningPersistent && persistent)
|
if(persistent)
|
||||||
{
|
{
|
||||||
if(dev.ScsiType == PeripheralDeviceTypes.MultiMediaDevice)
|
if(dev.ScsiType == PeripheralDeviceTypes.MultiMediaDevice)
|
||||||
{
|
{
|
||||||
@@ -526,17 +483,57 @@ namespace DiscImageChef.Core.Devices.Dumping
|
|||||||
}
|
}
|
||||||
|
|
||||||
dumpLog.WriteLine("Sending MODE SELECT to drive.");
|
dumpLog.WriteLine("Sending MODE SELECT to drive.");
|
||||||
sense = dev.ModeSelect(md6, out _, true, false, dev.Timeout, out _);
|
sense = dev.ModeSelect(md6, out byte[] senseBuf, true, false, dev.Timeout, out _);
|
||||||
if(sense) sense = dev.ModeSelect10(md10, out _, true, false, dev.Timeout, out _);
|
if(sense) sense = dev.ModeSelect10(md10, out senseBuf, true, false, dev.Timeout, out _);
|
||||||
|
|
||||||
|
if(sense)
|
||||||
|
{
|
||||||
|
DicConsole
|
||||||
|
.WriteLine("Drive did not accept MODE SELECT command for persistent error reading, try another drive.");
|
||||||
|
DicConsole.DebugWriteLine("Error: {0}", Sense.PrettifySense(senseBuf));
|
||||||
|
dumpLog.WriteLine("Drive did not accept MODE SELECT command for persistent error reading, try another drive.");
|
||||||
|
}
|
||||||
|
else runningPersistent = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
repeatRetry:
|
||||||
|
ulong[] tmpArray = resume.BadBlocks.ToArray();
|
||||||
|
foreach(ulong badSector in tmpArray)
|
||||||
|
{
|
||||||
|
if(aborted)
|
||||||
|
{
|
||||||
|
currentTry.Extents = ExtentsConverter.ToMetadata(extents);
|
||||||
|
dumpLog.WriteLine("Aborted!");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
DicConsole.Write("\rRetrying sector {0}, pass {1}, {3}{2}", badSector, pass + 1,
|
||||||
|
forward ? "forward" : "reverse",
|
||||||
|
runningPersistent ? "recovering partial data, " : "");
|
||||||
|
|
||||||
|
sense = scsiReader.ReadBlock(out readBuffer, badSector, out double cmdDuration);
|
||||||
|
totalDuration += cmdDuration;
|
||||||
|
|
||||||
runningPersistent = true;
|
|
||||||
if(!sense && !dev.Error)
|
if(!sense && !dev.Error)
|
||||||
{
|
{
|
||||||
pass--;
|
resume.BadBlocks.Remove(badSector);
|
||||||
|
extents.Add(badSector);
|
||||||
|
outputPlugin.WriteSector(readBuffer, badSector);
|
||||||
|
dumpLog.WriteLine("Correctly retried block {0} in pass {1}.", badSector, pass);
|
||||||
|
}
|
||||||
|
else if(runningPersistent) outputPlugin.WriteSector(readBuffer, badSector);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pass < retryPasses && !aborted && resume.BadBlocks.Count > 0)
|
||||||
|
{
|
||||||
|
pass++;
|
||||||
|
forward = !forward;
|
||||||
|
resume.BadBlocks.Sort();
|
||||||
|
resume.BadBlocks.Reverse();
|
||||||
goto repeatRetry;
|
goto repeatRetry;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if(runningPersistent && persistent && currentModePage.HasValue)
|
if(runningPersistent && currentModePage.HasValue)
|
||||||
{
|
{
|
||||||
Modes.DecodedMode md = new Modes.DecodedMode
|
Modes.DecodedMode md = new Modes.DecodedMode
|
||||||
{
|
{
|
||||||
@@ -872,12 +869,9 @@ namespace DiscImageChef.Core.Devices.Dumping
|
|||||||
if(!dev.IsRemovable || dev.IsUsb)
|
if(!dev.IsRemovable || dev.IsUsb)
|
||||||
if(dev.Type == DeviceType.ATAPI)
|
if(dev.Type == DeviceType.ATAPI)
|
||||||
sidecar.BlockMedia[0].Interface = "ATAPI";
|
sidecar.BlockMedia[0].Interface = "ATAPI";
|
||||||
else if(dev.IsUsb)
|
else if(dev.IsUsb) sidecar.BlockMedia[0].Interface = "USB";
|
||||||
sidecar.BlockMedia[0].Interface = "USB";
|
else if(dev.IsFireWire) sidecar.BlockMedia[0].Interface = "FireWire";
|
||||||
else if(dev.IsFireWire)
|
else sidecar.BlockMedia[0].Interface = "SCSI";
|
||||||
sidecar.BlockMedia[0].Interface = "FireWire";
|
|
||||||
else
|
|
||||||
sidecar.BlockMedia[0].Interface = "SCSI";
|
|
||||||
sidecar.BlockMedia[0].LogicalBlocks = (long)blocks;
|
sidecar.BlockMedia[0].LogicalBlocks = (long)blocks;
|
||||||
sidecar.BlockMedia[0].PhysicalBlockSize = (int)physicalBlockSize;
|
sidecar.BlockMedia[0].PhysicalBlockSize = (int)physicalBlockSize;
|
||||||
sidecar.BlockMedia[0].LogicalBlockSize = (int)logicalBlockSize;
|
sidecar.BlockMedia[0].LogicalBlockSize = (int)logicalBlockSize;
|
||||||
|
|||||||
Reference in New Issue
Block a user