🐛Fix sending error recovery MODE page to devices before trying damaged sectors. Fixes #169

This commit is contained in:
2018-04-02 23:08:26 +01:00
parent 8d8735fdcb
commit 2a9f5ff828
2 changed files with 174 additions and 180 deletions

View File

@@ -82,16 +82,16 @@ namespace DiscImageChef.Core.Devices.Dumping
/// <exception cref="NotImplementedException">If trying to dump scrambled sectors</exception>
/// <exception cref="InvalidOperationException">If the resume file is invalid</exception>
/// <exception cref="ArgumentOutOfRangeException">If the track type is unknown (never)</exception>
internal static void Dump(Device dev, string devicePath, IWritableImage outputPlugin, ushort retryPasses,
bool force, bool dumpRaw, bool persistent, bool stopOnError,
ref MediaType dskType,
ref
Resume resume, ref DumpLog dumpLog, bool dumpLeadIn,
Encoding encoding,
string
outputPrefix, string outputPath, Dictionary<string, string> formatOptions,
CICMMetadataType
preSidecar, uint skip, bool nometadata)
internal static void Dump(Device dev, string devicePath,
IWritableImage outputPlugin, ushort retryPasses,
bool force, bool dumpRaw,
bool persistent, bool stopOnError, ref MediaType dskType,
ref Resume resume, ref DumpLog dumpLog,
bool dumpLeadIn, Encoding encoding,
string outputPrefix, string outputPath,
Dictionary<string, string> formatOptions,
CICMMetadataType preSidecar, uint skip,
bool nometadata)
{
uint subSize;
DateTime start;
@@ -335,8 +335,7 @@ namespace DiscImageChef.Core.Devices.Dumping
toc.Value.TrackDescriptors.OrderBy(track => track.POINT).ToArray();
foreach(FullTOC.TrackDataDescriptor trk in sortedTracks.Where(trk => trk.ADR == 1 || trk.ADR == 4))
if(trk.POINT >= 0x01 &&
trk.POINT <= 0x63)
if(trk.POINT >= 0x01 && trk.POINT <= 0x63)
{
trackList.Add(new Track
{
@@ -732,8 +731,7 @@ namespace DiscImageChef.Core.Devices.Dumping
subSize = 0;
blockSize = SECTOR_SIZE + subSize;
for(int t = 0; t < tracks.Length; t++) tracks[t].TrackSubchannelType = TrackSubchannelType.None;
ret =
outputPlugin.SetTracks(tracks.ToList());
ret = outputPlugin.SetTracks(tracks.ToList());
if(!ret)
{
dumpLog.WriteLine("Error sending tracks to output image, not continuing.");
@@ -888,10 +886,9 @@ namespace DiscImageChef.Core.Devices.Dumping
end = DateTime.UtcNow;
mhddLog.Close();
ibgLog.Close(dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024,
blockSize * (double)(blocks + 1) /
1024 / (totalDuration / 1000), devicePath);
dumpLog.WriteLine("Dump finished in {0} seconds.",
(end - start).TotalSeconds);
blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000),
devicePath);
dumpLog.WriteLine("Dump finished in {0} seconds.", (end - start).TotalSeconds);
dumpLog.WriteLine("Average dump speed {0:F3} KiB/sec.",
(double)blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000));
dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.",
@@ -906,6 +903,44 @@ namespace DiscImageChef.Core.Devices.Dumping
bool forward = true;
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:
ulong[] tmpArray = resume.BadBlocks.ToArray();
foreach(ulong badSector in tmpArray)
@@ -960,42 +995,7 @@ namespace DiscImageChef.Core.Devices.Dumping
goto cdRepeatRetry;
}
Modes.ModePage? currentModePage = null;
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)
if(runningPersistent && currentModePage.HasValue)
{
Modes.DecodedMode md = new Modes.DecodedMode
{

View File

@@ -83,12 +83,11 @@ namespace DiscImageChef.Core.Devices.Dumping
bool persistent, bool stopOnError,
Dictionary<MediaTagType, byte[]> mediaTags, ref MediaType dskType,
bool opticalDisc,
ref Resume resume,
ref DumpLog dumpLog, Encoding encoding, string outputPrefix,
string outputPath,
Dictionary<string, string> formatOptions,
CICMMetadataType preSidecar,
uint skip, bool nometadata)
ref Resume resume, ref DumpLog dumpLog,
Encoding encoding, string outputPrefix,
string outputPath, Dictionary<string, string> formatOptions,
CICMMetadataType preSidecar, uint skip,
bool nometadata)
{
bool sense;
ulong blocks;
@@ -152,12 +151,9 @@ namespace DiscImageChef.Core.Devices.Dumping
{
mediaTags = new Dictionary<MediaTagType, byte[]>();
if(dev.IsUsb && dev.UsbDescriptors != null)
mediaTags.Add(MediaTagType.USB_Descriptors, null);
if(dev.Type == DeviceType.ATAPI)
mediaTags.Add(MediaTagType.ATAPI_IDENTIFY, null);
if(dev.IsPcmcia && dev.Cis != null)
mediaTags.Add(MediaTagType.PCMCIA_CIS, null);
if(dev.IsUsb && dev.UsbDescriptors != null) mediaTags.Add(MediaTagType.USB_Descriptors, null);
if(dev.Type == DeviceType.ATAPI) 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 _);
mediaTags.Add(MediaTagType.SCSI_INQUIRY, cmdBuf);
@@ -413,10 +409,9 @@ namespace DiscImageChef.Core.Devices.Dumping
DicConsole.WriteLine();
mhddLog.Close();
ibgLog.Close(dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024,
blockSize * (double)(blocks + 1) /
1024 / (totalDuration / 1000), devicePath);
dumpLog.WriteLine("Dump finished in {0} seconds.",
(end - start).TotalSeconds);
blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000),
devicePath);
dumpLog.WriteLine("Dump finished in {0} seconds.", (end - start).TotalSeconds);
dumpLog.WriteLine("Average dump speed {0:F3} KiB/sec.",
(double)blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000));
dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.",
@@ -429,49 +424,11 @@ namespace DiscImageChef.Core.Devices.Dumping
bool forward = true;
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;
byte[] md6;
byte[] md10;
if(!runningPersistent && persistent)
if(persistent)
{
if(dev.ScsiType == PeripheralDeviceTypes.MultiMediaDevice)
{
@@ -526,17 +483,57 @@ namespace DiscImageChef.Core.Devices.Dumping
}
dumpLog.WriteLine("Sending MODE SELECT to drive.");
sense = dev.ModeSelect(md6, out _, true, false, dev.Timeout, out _);
if(sense) sense = dev.ModeSelect10(md10, 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 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)
{
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;
}
}
else if(runningPersistent && persistent && currentModePage.HasValue)
if(runningPersistent && currentModePage.HasValue)
{
Modes.DecodedMode md = new Modes.DecodedMode
{
@@ -872,12 +869,9 @@ namespace DiscImageChef.Core.Devices.Dumping
if(!dev.IsRemovable || dev.IsUsb)
if(dev.Type == DeviceType.ATAPI)
sidecar.BlockMedia[0].Interface = "ATAPI";
else if(dev.IsUsb)
sidecar.BlockMedia[0].Interface = "USB";
else if(dev.IsFireWire)
sidecar.BlockMedia[0].Interface = "FireWire";
else
sidecar.BlockMedia[0].Interface = "SCSI";
else if(dev.IsUsb) sidecar.BlockMedia[0].Interface = "USB";
else if(dev.IsFireWire) sidecar.BlockMedia[0].Interface = "FireWire";
else sidecar.BlockMedia[0].Interface = "SCSI";
sidecar.BlockMedia[0].LogicalBlocks = (long)blocks;
sidecar.BlockMedia[0].PhysicalBlockSize = (int)physicalBlockSize;
sidecar.BlockMedia[0].LogicalBlockSize = (int)logicalBlockSize;