diff --git a/DiscImageChef.Core/Devices/Report/ATA.cs b/DiscImageChef.Core/Devices/Report/ATA.cs index 6d320c286..416a5e7c5 100644 --- a/DiscImageChef.Core/Devices/Report/ATA.cs +++ b/DiscImageChef.Core/Devices/Report/ATA.cs @@ -31,7 +31,6 @@ // ****************************************************************************/ using System; -using System.Collections.Generic; using DiscImageChef.CommonTypes.Metadata; using DiscImageChef.Console; using DiscImageChef.Decoders.ATA; @@ -39,460 +38,73 @@ using DiscImageChef.Devices; namespace DiscImageChef.Core.Devices.Report { - /// - /// Implements creating a report for an ATA device - /// - public static class Ata + public partial class DeviceReport { - /// - /// Creates a report of an ATA device - /// - /// Device - /// Device report - /// If debug is enabled - /// If device is removable - /// - public static void Report(Device dev, ref DeviceReportV2 report, bool debug, ref bool removable) + public TestedMedia ReportAtaMedia() { - if(report == null) return; + TestedMedia mediaTest = new TestedMedia(); + DicConsole.Write("Please write a description of the media type and press enter: "); + mediaTest.MediumTypeName = System.Console.ReadLine(); + DicConsole.Write("Please write the media model and press enter: "); + mediaTest.Model = System.Console.ReadLine(); - const uint TIMEOUT = 5; + mediaTest.MediaIsRecognized = true; DicConsole.WriteLine("Querying ATA IDENTIFY..."); + dev.AtaIdentify(out byte[] buffer, out _, dev.Timeout, out _); - dev.AtaIdentify(out byte[] buffer, out _, TIMEOUT, out _); + mediaTest.IdentifyData = buffer; + mediaTest.IdentifyDevice = Identify.Decode(buffer); - if(!Identify.Decode(buffer).HasValue) return; - - report.ATA = new CommonTypes.Metadata.Ata(); - report.ATA.IdentifyDevice = Identify.Decode(buffer); - ; - - if(report.ATA.IdentifyDevice == null) return; - - ConsoleKeyInfo pressedKey; - if((ushort)report.ATA.IdentifyDevice?.GeneralConfiguration == 0x848A) + if(mediaTest.IdentifyDevice.HasValue) { - report.CompactFlash = true; - removable = false; - } - else if(!removable && - report.ATA.IdentifyDevice?.GeneralConfiguration - .HasFlag(Identify.GeneralConfigurationBit.Removable) == true) - { - pressedKey = new ConsoleKeyInfo(); - while(pressedKey.Key != ConsoleKey.Y && pressedKey.Key != ConsoleKey.N) - { - DicConsole.Write("Is the media removable from the reading/writing elements? (Y/N): "); - pressedKey = System.Console.ReadKey(); - DicConsole.WriteLine(); - } + Identify.IdentifyDevice ataId = mediaTest.IdentifyDevice.Value; - removable = pressedKey.Key == ConsoleKey.Y; - } + if(ataId.UnformattedBPT != 0) mediaTest.UnformattedBPT = ataId.UnformattedBPT; - if(removable) - { - DicConsole.WriteLine("Please remove any media from the device and press any key when it is out."); - System.Console.ReadKey(true); - DicConsole.WriteLine("Querying ATA IDENTIFY..."); - dev.AtaIdentify(out buffer, out _, TIMEOUT, out _); - report.ATA.IdentifyDevice = Identify.Decode(buffer).Value; - } - - if(debug) report.ATA.Identify = buffer; - - if(removable) - { - List mediaTests = new List(); - - pressedKey = new ConsoleKeyInfo(); - while(pressedKey.Key != ConsoleKey.N) - { - pressedKey = new ConsoleKeyInfo(); - while(pressedKey.Key != ConsoleKey.Y && pressedKey.Key != ConsoleKey.N) - { - DicConsole.Write("Do you have media that you can insert in the drive? (Y/N): "); - pressedKey = System.Console.ReadKey(); - DicConsole.WriteLine(); - } - - if(pressedKey.Key != ConsoleKey.Y) continue; - - DicConsole.WriteLine("Please insert it in the drive and press any key when it is ready."); - System.Console.ReadKey(true); - - TestedMedia mediaTest = new TestedMedia(); - DicConsole.Write("Please write a description of the media type and press enter: "); - mediaTest.MediumTypeName = System.Console.ReadLine(); - DicConsole.Write("Please write the media model and press enter: "); - mediaTest.Model = System.Console.ReadLine(); - - mediaTest.MediaIsRecognized = true; - - DicConsole.WriteLine("Querying ATA IDENTIFY..."); - dev.AtaIdentify(out buffer, out _, TIMEOUT, out _); - - mediaTest.IdentifyData = buffer; - mediaTest.IdentifyDevice = Identify.Decode(buffer); - - if(mediaTest.IdentifyDevice.HasValue) - { - Identify.IdentifyDevice ataId = mediaTest.IdentifyDevice.Value; - - if(ataId.UnformattedBPT != 0) mediaTest.UnformattedBPT = ataId.UnformattedBPT; - - if(ataId.UnformattedBPS != 0) mediaTest.UnformattedBPS = ataId.UnformattedBPS; - - if(ataId.Cylinders > 0 && ataId.Heads > 0 && ataId.SectorsPerTrack > 0) - { - mediaTest.CHS = new Chs - { - Cylinders = ataId.Cylinders, Heads = ataId.Heads, Sectors = ataId.SectorsPerTrack - }; - mediaTest.Blocks = (ulong)(ataId.Cylinders * ataId.Heads * ataId.SectorsPerTrack); - } - - if(ataId.CurrentCylinders > 0 && ataId.CurrentHeads > 0 && ataId.CurrentSectorsPerTrack > 0) - { - mediaTest.CurrentCHS = new Chs - { - Cylinders = ataId.CurrentCylinders, - Heads = ataId.CurrentHeads, - Sectors = ataId.CurrentSectorsPerTrack - }; - if(mediaTest.Blocks == 0) - mediaTest.Blocks = - (ulong)(ataId.CurrentCylinders * ataId.CurrentHeads * ataId.CurrentSectorsPerTrack); - } - - if(ataId.Capabilities.HasFlag(Identify.CapabilitiesBit.LBASupport)) - { - mediaTest.LBASectors = ataId.LBASectors; - mediaTest.Blocks = ataId.LBASectors; - } - - if(ataId.CommandSet2.HasFlag(Identify.CommandSetBit2.LBA48)) - { - mediaTest.LBA48Sectors = ataId.LBA48Sectors; - mediaTest.Blocks = ataId.LBA48Sectors; - } - - if(ataId.NominalRotationRate != 0x0000 && ataId.NominalRotationRate != 0xFFFF) - if(ataId.NominalRotationRate == 0x0001) - mediaTest.SolidStateDevice = true; - else - { - mediaTest.SolidStateDevice = false; - mediaTest.NominalRotationRate = ataId.NominalRotationRate; - } - - uint logicalsectorsize; - uint physicalsectorsize; - if((ataId.PhysLogSectorSize & 0x8000) == 0x0000 && (ataId.PhysLogSectorSize & 0x4000) == 0x4000) - { - if((ataId.PhysLogSectorSize & 0x1000) == 0x1000) - if(ataId.LogicalSectorWords <= 255 || ataId.LogicalAlignment == 0xFFFF) - logicalsectorsize = 512; - else - logicalsectorsize = ataId.LogicalSectorWords * 2; - else logicalsectorsize = 512; - - if((ataId.PhysLogSectorSize & 0x2000) == 0x2000) - physicalsectorsize = - (uint)(logicalsectorsize * ((1 << ataId.PhysLogSectorSize) & 0xF)); - else physicalsectorsize = logicalsectorsize; - } - else - { - logicalsectorsize = 512; - physicalsectorsize = 512; - } - - mediaTest.BlockSize = logicalsectorsize; - if(physicalsectorsize != logicalsectorsize) - { - mediaTest.PhysicalBlockSize = physicalsectorsize; - - if((ataId.LogicalAlignment & 0x8000) == 0x0000 && - (ataId.LogicalAlignment & 0x4000) == 0x4000) - mediaTest.LogicalAlignment = (ushort)(ataId.LogicalAlignment & 0x3FFF); - } - - if(ataId.EccBytes != 0x0000 && ataId.EccBytes != 0xFFFF) - mediaTest.LongBlockSize = logicalsectorsize + ataId.EccBytes; - - if(ataId.UnformattedBPS > logicalsectorsize && - (!(ataId.EccBytes != 0x0000 && ataId.EccBytes != 0xFFFF) || mediaTest.LongBlockSize == 516)) - mediaTest.LongBlockSize = ataId.UnformattedBPS; - - if(ataId.CommandSet3.HasFlag(Identify.CommandSetBit3.MustBeSet) && - !ataId.CommandSet3.HasFlag(Identify.CommandSetBit3.MustBeClear) && - ataId.EnabledCommandSet3.HasFlag(Identify.CommandSetBit3.MediaSerial)) - { - mediaTest.CanReadMediaSerial = true; - if(!string.IsNullOrWhiteSpace(ataId.MediaManufacturer)) - mediaTest.Manufacturer = ataId.MediaManufacturer; - } - - ulong checkCorrectRead = BitConverter.ToUInt64(buffer, 0); - bool sense; - - DicConsole.WriteLine("Trying READ SECTOR(S) in CHS mode..."); - sense = dev.Read(out byte[] readBuf, out AtaErrorRegistersChs errorChs, false, 0, 0, 1, 1, - TIMEOUT, out _); - mediaTest.SupportsReadSectors = !sense && (errorChs.Status & 0x01) != 0x01 && - errorChs.Error == 0 && - readBuf.Length > 0; - DicConsole.DebugWriteLine("ATA Report", - "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", - sense, errorChs.Status, errorChs.Error, readBuf.Length); - if(debug) - DataFile.WriteTo("ATA Report", "readsectorschs", - "_debug_" + mediaTest.MediumTypeName + ".bin", "read results", readBuf); - - DicConsole.WriteLine("Trying READ SECTOR(S) RETRY in CHS mode..."); - sense = dev.Read(out readBuf, out errorChs, true, 0, 0, 1, 1, TIMEOUT, out _); - mediaTest.SupportsReadRetry = !sense && (errorChs.Status & 0x01) != 0x01 && - errorChs.Error == 0 && readBuf.Length > 0; - DicConsole.DebugWriteLine("ATA Report", - "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", - sense, errorChs.Status, errorChs.Error, readBuf.Length); - if(debug) - DataFile.WriteTo("ATA Report", "readsectorsretrychs", - "_debug_" + mediaTest.MediumTypeName + ".bin", "read results", readBuf); - - DicConsole.WriteLine("Trying READ DMA in CHS mode..."); - sense = dev.ReadDma(out readBuf, out errorChs, false, 0, 0, 1, 1, TIMEOUT, out _); - mediaTest.SupportsReadDma = !sense && (errorChs.Status & 0x01) != 0x01 && errorChs.Error == 0 && - readBuf.Length > 0; - DicConsole.DebugWriteLine("ATA Report", - "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", - sense, errorChs.Status, errorChs.Error, readBuf.Length); - if(debug) - DataFile.WriteTo("ATA Report", "readdmachs", "_debug_" + mediaTest.MediumTypeName + ".bin", - "read results", readBuf); - - DicConsole.WriteLine("Trying READ DMA RETRY in CHS mode..."); - sense = dev.ReadDma(out readBuf, out errorChs, true, 0, 0, 1, 1, TIMEOUT, out _); - mediaTest.SupportsReadDmaRetry = !sense && (errorChs.Status & 0x01) != 0x01 && - errorChs.Error == 0 && - readBuf.Length > 0; - DicConsole.DebugWriteLine("ATA Report", - "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", - sense, errorChs.Status, errorChs.Error, readBuf.Length); - if(debug) - DataFile.WriteTo("ATA Report", "readdmaretrychs", - "_debug_" + mediaTest.MediumTypeName + ".bin", "read results", readBuf); - - DicConsole.WriteLine("Trying SEEK in CHS mode..."); - sense = dev.Seek(out errorChs, 0, 0, 1, TIMEOUT, out _); - mediaTest.SupportsSeek = !sense && (errorChs.Status & 0x01) != 0x01 && errorChs.Error == 0; - DicConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}", - sense, errorChs.Status, errorChs.Error); - - DicConsole.WriteLine("Trying READ SECTOR(S) in LBA mode..."); - sense = dev.Read(out readBuf, out AtaErrorRegistersLba28 errorLba, false, 0, 1, TIMEOUT, out _); - mediaTest.SupportsReadLba = !sense && (errorLba.Status & 0x01) != 0x01 && errorLba.Error == 0 && - readBuf.Length > 0; - DicConsole.DebugWriteLine("ATA Report", - "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", - sense, errorChs.Status, errorChs.Error, readBuf.Length); - if(debug) - DataFile.WriteTo("ATA Report", "readsectors", "_debug_" + mediaTest.MediumTypeName + ".bin", - "read results", readBuf); - - DicConsole.WriteLine("Trying READ SECTOR(S) RETRY in LBA mode..."); - sense = dev.Read(out readBuf, out errorLba, true, 0, 1, TIMEOUT, out _); - mediaTest.SupportsReadRetryLba = !sense && (errorLba.Status & 0x01) != 0x01 && - errorLba.Error == 0 && - readBuf.Length > 0; - DicConsole.DebugWriteLine("ATA Report", - "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", - sense, errorChs.Status, errorChs.Error, readBuf.Length); - if(debug) - DataFile.WriteTo("ATA Report", "readsectorsretry", - "_debug_" + mediaTest.MediumTypeName + ".bin", "read results", readBuf); - - DicConsole.WriteLine("Trying READ DMA in LBA mode..."); - sense = dev.ReadDma(out readBuf, out errorLba, false, 0, 1, TIMEOUT, out _); - mediaTest.SupportsReadDmaLba = !sense && (errorLba.Status & 0x01) != 0x01 && - errorLba.Error == 0 && readBuf.Length > 0; - DicConsole.DebugWriteLine("ATA Report", - "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", - sense, errorChs.Status, errorChs.Error, readBuf.Length); - if(debug) - DataFile.WriteTo("ATA Report", "readdma", "_debug_" + mediaTest.MediumTypeName + ".bin", - "read results", readBuf); - - DicConsole.WriteLine("Trying READ DMA RETRY in LBA mode..."); - sense = dev.ReadDma(out readBuf, out errorLba, true, 0, 1, TIMEOUT, out _); - mediaTest.SupportsReadDmaRetryLba = - !sense && (errorLba.Status & 0x01) != 0x01 && errorLba.Error == 0 && readBuf.Length > 0; - DicConsole.DebugWriteLine("ATA Report", - "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", - sense, errorChs.Status, errorChs.Error, readBuf.Length); - if(debug) - DataFile.WriteTo("ATA Report", "readdmaretry", - "_debug_" + mediaTest.MediumTypeName + ".bin", "read results", readBuf); - - DicConsole.WriteLine("Trying SEEK in LBA mode..."); - sense = dev.Seek(out errorLba, 0, TIMEOUT, out _); - mediaTest.SupportsSeekLba = !sense && (errorLba.Status & 0x01) != 0x01 && errorLba.Error == 0; - DicConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}", - sense, errorChs.Status, errorChs.Error); - - DicConsole.WriteLine("Trying READ SECTOR(S) in LBA48 mode..."); - sense = dev.Read(out readBuf, out AtaErrorRegistersLba48 errorLba48, 0, 1, TIMEOUT, out _); - mediaTest.SupportsReadLba48 = !sense && (errorLba48.Status & 0x01) != 0x01 && - errorLba48.Error == 0 && - readBuf.Length > 0; - DicConsole.DebugWriteLine("ATA Report", - "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", - sense, errorChs.Status, errorChs.Error, readBuf.Length); - if(debug) - DataFile.WriteTo("ATA Report", "readsectors48", - "_debug_" + mediaTest.MediumTypeName + ".bin", "read results", readBuf); - - DicConsole.WriteLine("Trying READ DMA in LBA48 mode..."); - sense = dev.ReadDma(out readBuf, out errorLba48, 0, 1, TIMEOUT, out _); - mediaTest.SupportsReadDmaLba48 = !sense && (errorLba48.Status & 0x01) != 0x01 && - errorLba48.Error == 0 && - readBuf.Length > 0; - DicConsole.DebugWriteLine("ATA Report", - "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", - sense, errorChs.Status, errorChs.Error, readBuf.Length); - if(debug) - DataFile.WriteTo("ATA Report", "readdma48", "_debug_" + mediaTest.MediumTypeName + ".bin", - "read results", readBuf); - - // Send SET FEATURES before sending READ LONG commands, retrieve IDENTIFY again and - // check if ECC size changed. Sector is set to 1 because without it most drives just return - // CORRECTABLE ERROR for this command. - dev.SetFeatures(out _, AtaFeatures.EnableReadLongVendorLength, 0, 0, 1, 0, TIMEOUT, out _); - - dev.AtaIdentify(out buffer, out _, TIMEOUT, out _); - if(Identify.Decode(buffer).HasValue) - { - ataId = Identify.Decode(buffer).Value; - if(ataId.EccBytes != 0x0000 && ataId.EccBytes != 0xFFFF) - mediaTest.LongBlockSize = logicalsectorsize + ataId.EccBytes; - - if(ataId.UnformattedBPS > logicalsectorsize && - (!(ataId.EccBytes != 0x0000 && ataId.EccBytes != 0xFFFF) || - mediaTest.LongBlockSize == 516)) mediaTest.LongBlockSize = ataId.UnformattedBPS; - } - - DicConsole.WriteLine("Trying READ LONG in CHS mode..."); - sense = dev.ReadLong(out readBuf, out errorChs, false, 0, 0, 1, mediaTest.LongBlockSize ?? 0, - TIMEOUT, out _); - mediaTest.SupportsReadLong = !sense && (errorChs.Status & 0x01) != 0x01 && - errorChs.Error == 0 && readBuf.Length > 0 && - BitConverter.ToUInt64(readBuf, 0) != checkCorrectRead; - DicConsole.DebugWriteLine("ATA Report", - "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", - sense, errorChs.Status, errorChs.Error, readBuf.Length); - if(debug) - DataFile.WriteTo("ATA Report", "readlongchs", "_debug_" + mediaTest.MediumTypeName + ".bin", - "read results", readBuf); - - DicConsole.WriteLine("Trying READ LONG RETRY in CHS mode..."); - sense = dev.ReadLong(out readBuf, out errorChs, true, 0, 0, 1, mediaTest.LongBlockSize ?? 0, - TIMEOUT, out _); - mediaTest.SupportsReadLongRetry = - !sense && (errorChs.Status & 0x01) != 0x01 && errorChs.Error == 0 && readBuf.Length > 0 && - BitConverter.ToUInt64(readBuf, 0) != checkCorrectRead; - DicConsole.DebugWriteLine("ATA Report", - "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", - sense, errorChs.Status, errorChs.Error, readBuf.Length); - if(debug) - DataFile.WriteTo("ATA Report", "readlongretrychs", - "_debug_" + mediaTest.MediumTypeName + ".bin", "read results", readBuf); - - DicConsole.WriteLine("Trying READ LONG in LBA mode..."); - sense = dev.ReadLong(out readBuf, out errorLba, false, 0, mediaTest.LongBlockSize ?? 0, TIMEOUT, - out _); - mediaTest.SupportsReadLongLba = !sense && (errorLba.Status & 0x01) != 0x01 && - errorLba.Error == 0 && - readBuf.Length > 0 && - BitConverter.ToUInt64(readBuf, 0) != checkCorrectRead; - DicConsole.DebugWriteLine("ATA Report", - "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", - sense, errorChs.Status, errorChs.Error, readBuf.Length); - if(debug) - DataFile.WriteTo("ATA Report", "readlong", "_debug_" + mediaTest.MediumTypeName + ".bin", - "read results", readBuf); - - DicConsole.WriteLine("Trying READ LONG RETRY in LBA mode..."); - sense = dev.ReadLong(out readBuf, out errorLba, true, 0, mediaTest.LongBlockSize ?? 0, TIMEOUT, - out _); - mediaTest.SupportsReadLongRetryLba = - !sense && (errorLba.Status & 0x01) != 0x01 && errorLba.Error == 0 && readBuf.Length > 0 && - BitConverter.ToUInt64(readBuf, 0) != checkCorrectRead; - DicConsole.DebugWriteLine("ATA Report", - "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", - sense, errorChs.Status, errorChs.Error, readBuf.Length); - if(debug) - DataFile.WriteTo("ATA Report", "readlongretry", - "_debug_" + mediaTest.MediumTypeName + ".bin", "read results", readBuf); - } - else mediaTest.MediaIsRecognized = false; - - mediaTests.Add(mediaTest); - } - - report.ATA.RemovableMedias = mediaTests.ToArray(); - } - else - { - Identify.IdentifyDevice ataId = report.ATA.IdentifyDevice.Value; - - report.ATA.ReadCapabilities = new TestedMedia(); - - if(ataId.UnformattedBPT != 0) report.ATA.ReadCapabilities.UnformattedBPT = ataId.UnformattedBPT; - - if(ataId.UnformattedBPS != 0) report.ATA.ReadCapabilities.UnformattedBPS = ataId.UnformattedBPS; + if(ataId.UnformattedBPS != 0) mediaTest.UnformattedBPS = ataId.UnformattedBPS; if(ataId.Cylinders > 0 && ataId.Heads > 0 && ataId.SectorsPerTrack > 0) { - report.ATA.ReadCapabilities.CHS = new Chs + mediaTest.CHS = new Chs { Cylinders = ataId.Cylinders, Heads = ataId.Heads, Sectors = ataId.SectorsPerTrack }; - report.ATA.ReadCapabilities.Blocks = (ulong)(ataId.Cylinders * ataId.Heads * ataId.SectorsPerTrack); + mediaTest.Blocks = (ulong)(ataId.Cylinders * ataId.Heads * ataId.SectorsPerTrack); } if(ataId.CurrentCylinders > 0 && ataId.CurrentHeads > 0 && ataId.CurrentSectorsPerTrack > 0) { - report.ATA.ReadCapabilities.CurrentCHS = new Chs + mediaTest.CurrentCHS = new Chs { Cylinders = ataId.CurrentCylinders, Heads = ataId.CurrentHeads, Sectors = ataId.CurrentSectorsPerTrack }; - report.ATA.ReadCapabilities.Blocks = - (ulong)(ataId.CurrentCylinders * ataId.CurrentHeads * ataId.CurrentSectorsPerTrack); + if(mediaTest.Blocks == 0) + mediaTest.Blocks = + (ulong)(ataId.CurrentCylinders * ataId.CurrentHeads * ataId.CurrentSectorsPerTrack); } if(ataId.Capabilities.HasFlag(Identify.CapabilitiesBit.LBASupport)) { - report.ATA.ReadCapabilities.LBASectors = ataId.LBASectors; - report.ATA.ReadCapabilities.Blocks = ataId.LBASectors; + mediaTest.LBASectors = ataId.LBASectors; + mediaTest.Blocks = ataId.LBASectors; } if(ataId.CommandSet2.HasFlag(Identify.CommandSetBit2.LBA48)) { - report.ATA.ReadCapabilities.LBA48Sectors = ataId.LBA48Sectors; - report.ATA.ReadCapabilities.Blocks = ataId.LBA48Sectors; + mediaTest.LBA48Sectors = ataId.LBA48Sectors; + mediaTest.Blocks = ataId.LBA48Sectors; } if(ataId.NominalRotationRate != 0x0000 && ataId.NominalRotationRate != 0xFFFF) if(ataId.NominalRotationRate == 0x0001) - report.ATA.ReadCapabilities.SolidStateDevice = true; + mediaTest.SolidStateDevice = true; else { - report.ATA.ReadCapabilities.SolidStateDevice = false; - report.ATA.ReadCapabilities.NominalRotationRate = ataId.NominalRotationRate; + mediaTest.SolidStateDevice = false; + mediaTest.NominalRotationRate = ataId.NominalRotationRate; } uint logicalsectorsize; @@ -507,7 +119,7 @@ namespace DiscImageChef.Core.Devices.Report else logicalsectorsize = 512; if((ataId.PhysLogSectorSize & 0x2000) == 0x2000) - physicalsectorsize = logicalsectorsize * (uint)Math.Pow(2, ataId.PhysLogSectorSize & 0xF); + physicalsectorsize = (uint)(logicalsectorsize * ((1 << ataId.PhysLogSectorSize) & 0xF)); else physicalsectorsize = logicalsectorsize; } else @@ -516,230 +128,509 @@ namespace DiscImageChef.Core.Devices.Report physicalsectorsize = 512; } - report.ATA.ReadCapabilities.BlockSize = logicalsectorsize; + mediaTest.BlockSize = logicalsectorsize; if(physicalsectorsize != logicalsectorsize) { - report.ATA.ReadCapabilities.PhysicalBlockSize = physicalsectorsize; + mediaTest.PhysicalBlockSize = physicalsectorsize; if((ataId.LogicalAlignment & 0x8000) == 0x0000 && (ataId.LogicalAlignment & 0x4000) == 0x4000) - report.ATA.ReadCapabilities.LogicalAlignment = (ushort)(ataId.LogicalAlignment & 0x3FFF); + mediaTest.LogicalAlignment = (ushort)(ataId.LogicalAlignment & 0x3FFF); } if(ataId.EccBytes != 0x0000 && ataId.EccBytes != 0xFFFF) - report.ATA.ReadCapabilities.LongBlockSize = logicalsectorsize + ataId.EccBytes; + mediaTest.LongBlockSize = logicalsectorsize + ataId.EccBytes; if(ataId.UnformattedBPS > logicalsectorsize && - (!(ataId.EccBytes != 0x0000 && ataId.EccBytes != 0xFFFF) || - report.ATA.ReadCapabilities.LongBlockSize == 516)) - report.ATA.ReadCapabilities.LongBlockSize = ataId.UnformattedBPS; + (!(ataId.EccBytes != 0x0000 && ataId.EccBytes != 0xFFFF) || mediaTest.LongBlockSize == 516)) + mediaTest.LongBlockSize = ataId.UnformattedBPS; if(ataId.CommandSet3.HasFlag(Identify.CommandSetBit3.MustBeSet) && !ataId.CommandSet3.HasFlag(Identify.CommandSetBit3.MustBeClear) && ataId.EnabledCommandSet3.HasFlag(Identify.CommandSetBit3.MediaSerial)) { - report.ATA.ReadCapabilities.CanReadMediaSerial = true; + mediaTest.CanReadMediaSerial = true; if(!string.IsNullOrWhiteSpace(ataId.MediaManufacturer)) - report.ATA.ReadCapabilities.Manufacturer = ataId.MediaManufacturer; + mediaTest.Manufacturer = ataId.MediaManufacturer; } ulong checkCorrectRead = BitConverter.ToUInt64(buffer, 0); bool sense; DicConsole.WriteLine("Trying READ SECTOR(S) in CHS mode..."); - sense = dev.Read(out byte[] readBuf, out AtaErrorRegistersChs errorChs, false, 0, 0, 1, 1, TIMEOUT, + sense = dev.Read(out byte[] readBuf, out AtaErrorRegistersChs errorChs, false, 0, 0, 1, 1, dev.Timeout, out _); - report.ATA.ReadCapabilities.SupportsReadSectors = - !sense && (errorChs.Status & 0x01) != 0x01 && errorChs.Error == 0 && readBuf.Length > 0; + mediaTest.SupportsReadSectors = !sense && (errorChs.Status & 0x01) != 0x01 && errorChs.Error == 0 && + readBuf.Length > 0; DicConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", sense, errorChs.Status, errorChs.Error, readBuf.Length); if(debug) - DataFile.WriteTo("ATA Report", "readsectorschs", - "_debug_" + report.ATA.IdentifyDevice?.Model + ".bin", "read results", readBuf); + DataFile.WriteTo("ATA Report", "readsectorschs", "_debug_" + mediaTest.MediumTypeName + ".bin", + "read results", readBuf); DicConsole.WriteLine("Trying READ SECTOR(S) RETRY in CHS mode..."); - sense = dev.Read(out readBuf, out errorChs, true, 0, 0, 1, 1, TIMEOUT, out _); - report.ATA.ReadCapabilities.SupportsReadRetry = - !sense && (errorChs.Status & 0x01) != 0x01 && errorChs.Error == 0 && readBuf.Length > 0; + sense = dev.Read(out readBuf, out errorChs, true, 0, 0, 1, 1, dev.Timeout, out _); + mediaTest.SupportsReadRetry = !sense && (errorChs.Status & 0x01) != 0x01 && errorChs.Error == 0 && + readBuf.Length > 0; DicConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", sense, errorChs.Status, errorChs.Error, readBuf.Length); if(debug) - DataFile.WriteTo("ATA Report", "readsectorsretrychs", - "_debug_" + report.ATA.IdentifyDevice?.Model + ".bin", "read results", readBuf); + DataFile.WriteTo("ATA Report", "readsectorsretrychs", "_debug_" + mediaTest.MediumTypeName + ".bin", + "read results", readBuf); DicConsole.WriteLine("Trying READ DMA in CHS mode..."); - sense = dev.ReadDma(out readBuf, out errorChs, false, 0, 0, 1, 1, TIMEOUT, out _); - report.ATA.ReadCapabilities.SupportsReadDma = - !sense && (errorChs.Status & 0x01) != 0x01 && errorChs.Error == 0 && readBuf.Length > 0; + sense = dev.ReadDma(out readBuf, out errorChs, false, 0, 0, 1, 1, dev.Timeout, out _); + mediaTest.SupportsReadDma = !sense && (errorChs.Status & 0x01) != 0x01 && errorChs.Error == 0 && + readBuf.Length > 0; DicConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", sense, errorChs.Status, errorChs.Error, readBuf.Length); if(debug) - DataFile.WriteTo("ATA Report", "readdmachs", "_debug_" + report.ATA.IdentifyDevice?.Model + ".bin", + DataFile.WriteTo("ATA Report", "readdmachs", "_debug_" + mediaTest.MediumTypeName + ".bin", "read results", readBuf); DicConsole.WriteLine("Trying READ DMA RETRY in CHS mode..."); - sense = dev.ReadDma(out readBuf, out errorChs, true, 0, 0, 1, 1, TIMEOUT, out _); - report.ATA.ReadCapabilities.SupportsReadDmaRetry = - !sense && (errorChs.Status & 0x01) != 0x01 && errorChs.Error == 0 && readBuf.Length > 0; + sense = dev.ReadDma(out readBuf, out errorChs, true, 0, 0, 1, 1, dev.Timeout, out _); + mediaTest.SupportsReadDmaRetry = !sense && (errorChs.Status & 0x01) != 0x01 && errorChs.Error == 0 && + readBuf.Length > 0; DicConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", sense, errorChs.Status, errorChs.Error, readBuf.Length); if(debug) - DataFile.WriteTo("ATA Report", "readdmaretrychs", - "_debug_" + report.ATA.IdentifyDevice?.Model + ".bin", "read results", readBuf); + DataFile.WriteTo("ATA Report", "readdmaretrychs", "_debug_" + mediaTest.MediumTypeName + ".bin", + "read results", readBuf); DicConsole.WriteLine("Trying SEEK in CHS mode..."); - sense = dev.Seek(out errorChs, 0, 0, 1, TIMEOUT, out _); - report.ATA.ReadCapabilities.SupportsSeek = - !sense && (errorChs.Status & 0x01) != 0x01 && errorChs.Error == 0; + sense = dev.Seek(out errorChs, 0, 0, 1, dev.Timeout, out _); + mediaTest.SupportsSeek = !sense && (errorChs.Status & 0x01) != 0x01 && errorChs.Error == 0; DicConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}", sense, errorChs.Status, errorChs.Error); DicConsole.WriteLine("Trying READ SECTOR(S) in LBA mode..."); - sense = dev.Read(out readBuf, out AtaErrorRegistersLba28 errorLba, false, 0, 1, TIMEOUT, out _); - report.ATA.ReadCapabilities.SupportsReadLba = - !sense && (errorLba.Status & 0x01) != 0x01 && errorLba.Error == 0 && readBuf.Length > 0; + sense = dev.Read(out readBuf, out AtaErrorRegistersLba28 errorLba, false, 0, 1, dev.Timeout, out _); + mediaTest.SupportsReadLba = !sense && (errorLba.Status & 0x01) != 0x01 && errorLba.Error == 0 && + readBuf.Length > 0; DicConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", sense, - errorLba.Status, errorLba.Error, readBuf.Length); + errorChs.Status, errorChs.Error, readBuf.Length); if(debug) - DataFile.WriteTo("ATA Report", "readsectors", "_debug_" + report.ATA.IdentifyDevice?.Model + ".bin", + DataFile.WriteTo("ATA Report", "readsectors", "_debug_" + mediaTest.MediumTypeName + ".bin", "read results", readBuf); DicConsole.WriteLine("Trying READ SECTOR(S) RETRY in LBA mode..."); - sense = dev.Read(out readBuf, out errorLba, true, 0, 1, TIMEOUT, out _); - report.ATA.ReadCapabilities.SupportsReadRetryLba = - !sense && (errorLba.Status & 0x01) != 0x01 && errorLba.Error == 0 && readBuf.Length > 0; + sense = dev.Read(out readBuf, out errorLba, true, 0, 1, dev.Timeout, out _); + mediaTest.SupportsReadRetryLba = !sense && (errorLba.Status & 0x01) != 0x01 && errorLba.Error == 0 && + readBuf.Length > 0; DicConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", sense, - errorLba.Status, errorLba.Error, readBuf.Length); + errorChs.Status, errorChs.Error, readBuf.Length); if(debug) - DataFile.WriteTo("ATA Report", "readsectorsretry", - "_debug_" + report.ATA.IdentifyDevice?.Model + ".bin", "read results", readBuf); + DataFile.WriteTo("ATA Report", "readsectorsretry", "_debug_" + mediaTest.MediumTypeName + ".bin", + "read results", readBuf); DicConsole.WriteLine("Trying READ DMA in LBA mode..."); - sense = dev.ReadDma(out readBuf, out errorLba, false, 0, 1, TIMEOUT, out _); - report.ATA.ReadCapabilities.SupportsReadDmaLba = - !sense && (errorLba.Status & 0x01) != 0x01 && errorLba.Error == 0 && readBuf.Length > 0; + sense = dev.ReadDma(out readBuf, out errorLba, false, 0, 1, dev.Timeout, out _); + mediaTest.SupportsReadDmaLba = !sense && (errorLba.Status & 0x01) != 0x01 && errorLba.Error == 0 && + readBuf.Length > 0; DicConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", sense, - errorLba.Status, errorLba.Error, readBuf.Length); + errorChs.Status, errorChs.Error, readBuf.Length); if(debug) - DataFile.WriteTo("ATA Report", "readdma", "_debug_" + report.ATA.IdentifyDevice?.Model + ".bin", + DataFile.WriteTo("ATA Report", "readdma", "_debug_" + mediaTest.MediumTypeName + ".bin", "read results", readBuf); DicConsole.WriteLine("Trying READ DMA RETRY in LBA mode..."); - sense = dev.ReadDma(out readBuf, out errorLba, true, 0, 1, TIMEOUT, out _); - report.ATA.ReadCapabilities.SupportsReadDmaRetryLba = - !sense && (errorLba.Status & 0x01) != 0x01 && errorLba.Error == 0 && readBuf.Length > 0; + sense = dev.ReadDma(out readBuf, out errorLba, true, 0, 1, dev.Timeout, out _); + mediaTest.SupportsReadDmaRetryLba = !sense && (errorLba.Status & 0x01) != 0x01 && errorLba.Error == 0 && + readBuf.Length > 0; DicConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", sense, - errorLba.Status, errorLba.Error, readBuf.Length); + errorChs.Status, errorChs.Error, readBuf.Length); if(debug) - DataFile.WriteTo("ATA Report", "readdmaretry", - "_debug_" + report.ATA.IdentifyDevice?.Model + ".bin", "read results", readBuf); + DataFile.WriteTo("ATA Report", "readdmaretry", "_debug_" + mediaTest.MediumTypeName + ".bin", + "read results", readBuf); DicConsole.WriteLine("Trying SEEK in LBA mode..."); - sense = dev.Seek(out errorLba, 0, TIMEOUT, out _); - report.ATA.ReadCapabilities.SupportsSeekLba = - !sense && (errorLba.Status & 0x01) != 0x01 && errorLba.Error == 0; + sense = dev.Seek(out errorLba, 0, dev.Timeout, out _); + mediaTest.SupportsSeekLba = !sense && (errorLba.Status & 0x01) != 0x01 && errorLba.Error == 0; DicConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}", sense, - errorLba.Status, errorLba.Error); + errorChs.Status, errorChs.Error); DicConsole.WriteLine("Trying READ SECTOR(S) in LBA48 mode..."); - sense = dev.Read(out readBuf, out AtaErrorRegistersLba48 errorLba48, 0, 1, TIMEOUT, out _); - report.ATA.ReadCapabilities.SupportsReadLba48 = - !sense && (errorLba48.Status & 0x01) != 0x01 && errorLba48.Error == 0 && readBuf.Length > 0; + sense = dev.Read(out readBuf, out AtaErrorRegistersLba48 errorLba48, 0, 1, dev.Timeout, out _); + mediaTest.SupportsReadLba48 = !sense && (errorLba48.Status & 0x01) != 0x01 && errorLba48.Error == 0 && + readBuf.Length > 0; DicConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", sense, - errorLba48.Status, errorLba48.Error, readBuf.Length); + errorChs.Status, errorChs.Error, readBuf.Length); if(debug) - DataFile.WriteTo("ATA Report", "readsectors48", - "_debug_" + report.ATA.IdentifyDevice?.Model + ".bin", "read results", readBuf); + DataFile.WriteTo("ATA Report", "readsectors48", "_debug_" + mediaTest.MediumTypeName + ".bin", + "read results", readBuf); DicConsole.WriteLine("Trying READ DMA in LBA48 mode..."); - sense = dev.ReadDma(out readBuf, out errorLba48, 0, 1, TIMEOUT, out _); - report.ATA.ReadCapabilities.SupportsReadDmaLba48 = - !sense && (errorLba48.Status & 0x01) != 0x01 && errorLba48.Error == 0 && readBuf.Length > 0; + sense = dev.ReadDma(out readBuf, out errorLba48, 0, 1, dev.Timeout, out _); + mediaTest.SupportsReadDmaLba48 = !sense && (errorLba48.Status & 0x01) != 0x01 && + errorLba48.Error == 0 && readBuf.Length > 0; DicConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", sense, - errorLba48.Status, errorLba48.Error, readBuf.Length); + errorChs.Status, errorChs.Error, readBuf.Length); if(debug) - DataFile.WriteTo("ATA Report", "readdma48", "_debug_" + report.ATA.IdentifyDevice?.Model + ".bin", + DataFile.WriteTo("ATA Report", "readdma48", "_debug_" + mediaTest.MediumTypeName + ".bin", "read results", readBuf); // Send SET FEATURES before sending READ LONG commands, retrieve IDENTIFY again and // check if ECC size changed. Sector is set to 1 because without it most drives just return // CORRECTABLE ERROR for this command. - dev.SetFeatures(out _, AtaFeatures.EnableReadLongVendorLength, 0, 0, 1, 0, TIMEOUT, out _); + dev.SetFeatures(out _, AtaFeatures.EnableReadLongVendorLength, 0, 0, 1, 0, dev.Timeout, out _); - dev.AtaIdentify(out buffer, out _, TIMEOUT, out _); + dev.AtaIdentify(out buffer, out _, dev.Timeout, out _); if(Identify.Decode(buffer).HasValue) { ataId = Identify.Decode(buffer).Value; if(ataId.EccBytes != 0x0000 && ataId.EccBytes != 0xFFFF) - report.ATA.ReadCapabilities.LongBlockSize = logicalsectorsize + ataId.EccBytes; + mediaTest.LongBlockSize = logicalsectorsize + ataId.EccBytes; if(ataId.UnformattedBPS > logicalsectorsize && - (!(ataId.EccBytes != 0x0000 && ataId.EccBytes != 0xFFFF) || - report.ATA.ReadCapabilities.LongBlockSize == 516)) - report.ATA.ReadCapabilities.LongBlockSize = ataId.UnformattedBPS; + (!(ataId.EccBytes != 0x0000 && ataId.EccBytes != 0xFFFF) || mediaTest.LongBlockSize == 516)) + mediaTest.LongBlockSize = ataId.UnformattedBPS; } DicConsole.WriteLine("Trying READ LONG in CHS mode..."); - sense = dev.ReadLong(out readBuf, out errorChs, false, 0, 0, 1, - report.ATA.ReadCapabilities.LongBlockSize ?? 0, TIMEOUT, out _); - report.ATA.ReadCapabilities.SupportsReadLong = - !sense && (errorChs.Status & 0x01) != 0x01 && errorChs.Error == 0 && readBuf.Length > 0 && - BitConverter.ToUInt64(readBuf, 0) != checkCorrectRead; + sense = dev.ReadLong(out readBuf, out errorChs, false, 0, 0, 1, mediaTest.LongBlockSize ?? 0, + dev.Timeout, out _); + mediaTest.SupportsReadLong = !sense && (errorChs.Status & 0x01) != 0x01 && errorChs.Error == 0 && + readBuf.Length > 0 && + BitConverter.ToUInt64(readBuf, 0) != checkCorrectRead; DicConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", sense, errorChs.Status, errorChs.Error, readBuf.Length); if(debug) - DataFile.WriteTo("ATA Report", "readlongchs", "_debug_" + report.ATA.IdentifyDevice?.Model + ".bin", + DataFile.WriteTo("ATA Report", "readlongchs", "_debug_" + mediaTest.MediumTypeName + ".bin", "read results", readBuf); DicConsole.WriteLine("Trying READ LONG RETRY in CHS mode..."); - sense = dev.ReadLong(out readBuf, out errorChs, true, 0, 0, 1, - report.ATA.ReadCapabilities.LongBlockSize ?? 0, TIMEOUT, out _); - report.ATA.ReadCapabilities.SupportsReadLongRetry = - !sense && (errorChs.Status & 0x01) != 0x01 && errorChs.Error == 0 && readBuf.Length > 0 && - BitConverter.ToUInt64(readBuf, 0) != checkCorrectRead; + sense = dev.ReadLong(out readBuf, out errorChs, true, 0, 0, 1, mediaTest.LongBlockSize ?? 0, + dev.Timeout, out _); + mediaTest.SupportsReadLongRetry = !sense && (errorChs.Status & 0x01) != 0x01 && errorChs.Error == 0 && + readBuf.Length > 0 && + BitConverter.ToUInt64(readBuf, 0) != + checkCorrectRead; DicConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", sense, errorChs.Status, errorChs.Error, readBuf.Length); if(debug) - DataFile.WriteTo("ATA Report", "readlongretrychs", - "_debug_" + report.ATA.IdentifyDevice?.Model + ".bin", "read results", readBuf); + DataFile.WriteTo("ATA Report", "readlongretrychs", "_debug_" + mediaTest.MediumTypeName + ".bin", + "read results", readBuf); DicConsole.WriteLine("Trying READ LONG in LBA mode..."); - sense = dev.ReadLong(out readBuf, out errorLba, false, 0, - report.ATA.ReadCapabilities.LongBlockSize ?? 0, TIMEOUT, out _); - report.ATA.ReadCapabilities.SupportsReadLongLba = - !sense && (errorLba.Status & 0x01) != 0x01 && errorLba.Error == 0 && readBuf.Length > 0 && - BitConverter.ToUInt64(readBuf, 0) != checkCorrectRead; + sense = dev.ReadLong(out readBuf, out errorLba, false, 0, mediaTest.LongBlockSize ?? 0, dev.Timeout, + out _); + mediaTest.SupportsReadLongLba = !sense && (errorLba.Status & 0x01) != 0x01 && errorLba.Error == 0 && + readBuf.Length > 0 && + BitConverter.ToUInt64(readBuf, 0) != checkCorrectRead; DicConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", sense, - errorLba.Status, errorLba.Error, readBuf.Length); + errorChs.Status, errorChs.Error, readBuf.Length); if(debug) - DataFile.WriteTo("ATA Report", "readlong", "_debug_" + report.ATA.IdentifyDevice?.Model + ".bin", + DataFile.WriteTo("ATA Report", "readlong", "_debug_" + mediaTest.MediumTypeName + ".bin", "read results", readBuf); DicConsole.WriteLine("Trying READ LONG RETRY in LBA mode..."); - sense = dev.ReadLong(out readBuf, out errorLba, true, 0, report.ATA.ReadCapabilities.LongBlockSize ?? 0, - TIMEOUT, out _); - report.ATA.ReadCapabilities.SupportsReadLongRetryLba = - !sense && (errorLba.Status & 0x01) != 0x01 && errorLba.Error == 0 && readBuf.Length > 0 && - BitConverter.ToUInt64(readBuf, 0) != checkCorrectRead; + sense = dev.ReadLong(out readBuf, out errorLba, true, 0, mediaTest.LongBlockSize ?? 0, dev.Timeout, + out _); + mediaTest.SupportsReadLongRetryLba = !sense && (errorLba.Status & 0x01) != 0x01 && + errorLba.Error == 0 && readBuf.Length > 0 && + BitConverter.ToUInt64(readBuf, 0) != checkCorrectRead; DicConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", sense, - errorLba.Status, errorLba.Error, readBuf.Length); + errorChs.Status, errorChs.Error, readBuf.Length); if(debug) - DataFile.WriteTo("ATA Report", "readlongretry", - "_debug_" + report.ATA.IdentifyDevice?.Model + ".bin", "read results", readBuf); + DataFile.WriteTo("ATA Report", "readlongretry", "_debug_" + mediaTest.MediumTypeName + ".bin", + "read results", readBuf); } + else mediaTest.MediaIsRecognized = false; + + return mediaTest; + } + + /// + /// Creates a report of an ATA device + /// + public TestedMedia ReportAta(Identify.IdentifyDevice ataId) + { + TestedMedia capabilities = new TestedMedia(); + + if(ataId.UnformattedBPT != 0) capabilities.UnformattedBPT = ataId.UnformattedBPT; + + if(ataId.UnformattedBPS != 0) capabilities.UnformattedBPS = ataId.UnformattedBPS; + + if(ataId.Cylinders > 0 && ataId.Heads > 0 && ataId.SectorsPerTrack > 0) + { + capabilities.CHS = new Chs + { + Cylinders = ataId.Cylinders, Heads = ataId.Heads, Sectors = ataId.SectorsPerTrack + }; + capabilities.Blocks = (ulong)(ataId.Cylinders * ataId.Heads * ataId.SectorsPerTrack); + } + + if(ataId.CurrentCylinders > 0 && ataId.CurrentHeads > 0 && ataId.CurrentSectorsPerTrack > 0) + { + capabilities.CurrentCHS = new Chs + { + Cylinders = ataId.CurrentCylinders, + Heads = ataId.CurrentHeads, + Sectors = ataId.CurrentSectorsPerTrack + }; + capabilities.Blocks = + (ulong)(ataId.CurrentCylinders * ataId.CurrentHeads * ataId.CurrentSectorsPerTrack); + } + + if(ataId.Capabilities.HasFlag(Identify.CapabilitiesBit.LBASupport)) + { + capabilities.LBASectors = ataId.LBASectors; + capabilities.Blocks = ataId.LBASectors; + } + + if(ataId.CommandSet2.HasFlag(Identify.CommandSetBit2.LBA48)) + { + capabilities.LBA48Sectors = ataId.LBA48Sectors; + capabilities.Blocks = ataId.LBA48Sectors; + } + + if(ataId.NominalRotationRate != 0x0000 && ataId.NominalRotationRate != 0xFFFF) + if(ataId.NominalRotationRate == 0x0001) + capabilities.SolidStateDevice = true; + else + { + capabilities.SolidStateDevice = false; + capabilities.NominalRotationRate = ataId.NominalRotationRate; + } + + uint logicalsectorsize; + uint physicalsectorsize; + if((ataId.PhysLogSectorSize & 0x8000) == 0x0000 && (ataId.PhysLogSectorSize & 0x4000) == 0x4000) + { + if((ataId.PhysLogSectorSize & 0x1000) == 0x1000) + if(ataId.LogicalSectorWords <= 255 || ataId.LogicalAlignment == 0xFFFF) + logicalsectorsize = 512; + else + logicalsectorsize = ataId.LogicalSectorWords * 2; + else logicalsectorsize = 512; + + if((ataId.PhysLogSectorSize & 0x2000) == 0x2000) + physicalsectorsize = logicalsectorsize * (uint)Math.Pow(2, ataId.PhysLogSectorSize & 0xF); + else physicalsectorsize = logicalsectorsize; + } + else + { + logicalsectorsize = 512; + physicalsectorsize = 512; + } + + capabilities.BlockSize = logicalsectorsize; + if(physicalsectorsize != logicalsectorsize) + { + capabilities.PhysicalBlockSize = physicalsectorsize; + + if((ataId.LogicalAlignment & 0x8000) == 0x0000 && (ataId.LogicalAlignment & 0x4000) == 0x4000) + capabilities.LogicalAlignment = (ushort)(ataId.LogicalAlignment & 0x3FFF); + } + + if(ataId.EccBytes != 0x0000 && ataId.EccBytes != 0xFFFF) + capabilities.LongBlockSize = logicalsectorsize + ataId.EccBytes; + + if(ataId.UnformattedBPS > logicalsectorsize && + (!(ataId.EccBytes != 0x0000 && ataId.EccBytes != 0xFFFF) || capabilities.LongBlockSize == 516)) + capabilities.LongBlockSize = ataId.UnformattedBPS; + + if(ataId.CommandSet3.HasFlag(Identify.CommandSetBit3.MustBeSet) && + !ataId.CommandSet3.HasFlag(Identify.CommandSetBit3.MustBeClear) && + ataId.EnabledCommandSet3.HasFlag(Identify.CommandSetBit3.MediaSerial)) + { + capabilities.CanReadMediaSerial = true; + if(!string.IsNullOrWhiteSpace(ataId.MediaManufacturer)) + capabilities.Manufacturer = ataId.MediaManufacturer; + } + + ulong checkCorrectRead = 0; + bool sense; + + DicConsole.WriteLine("Trying READ SECTOR(S) in CHS mode..."); + sense = dev.Read(out byte[] readBuf, out AtaErrorRegistersChs errorChs, false, 0, 0, 1, 1, dev.Timeout, + out _); + capabilities.SupportsReadSectors = !sense && (errorChs.Status & 0x01) != 0x01 && errorChs.Error == 0 && + readBuf.Length > 0; + DicConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", + sense, errorChs.Status, errorChs.Error, readBuf.Length); + if(debug) + DataFile.WriteTo("ATA Report", "readsectorschs", "_debug_" + dev.Model + ".bin", "read results", + readBuf); + + DicConsole.WriteLine("Trying READ SECTOR(S) RETRY in CHS mode..."); + sense = dev.Read(out readBuf, out errorChs, true, 0, 0, 1, 1, dev.Timeout, out _); + capabilities.SupportsReadRetry = + !sense && (errorChs.Status & 0x01) != 0x01 && errorChs.Error == 0 && readBuf.Length > 0; + DicConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", + sense, errorChs.Status, errorChs.Error, readBuf.Length); + if(debug) + DataFile.WriteTo("ATA Report", "readsectorsretrychs", "_debug_" + dev.Model + ".bin", "read results", + readBuf); + + DicConsole.WriteLine("Trying READ DMA in CHS mode..."); + sense = dev.ReadDma(out readBuf, out errorChs, false, 0, 0, 1, 1, dev.Timeout, out _); + capabilities.SupportsReadDma = + !sense && (errorChs.Status & 0x01) != 0x01 && errorChs.Error == 0 && readBuf.Length > 0; + DicConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", + sense, errorChs.Status, errorChs.Error, readBuf.Length); + if(debug) + DataFile.WriteTo("ATA Report", "readdmachs", "_debug_" + dev.Model + ".bin", "read results", readBuf); + + DicConsole.WriteLine("Trying READ DMA RETRY in CHS mode..."); + sense = dev.ReadDma(out readBuf, out errorChs, true, 0, 0, 1, 1, dev.Timeout, out _); + capabilities.SupportsReadDmaRetry = !sense && (errorChs.Status & 0x01) != 0x01 && errorChs.Error == 0 && + readBuf.Length > 0; + DicConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", + sense, errorChs.Status, errorChs.Error, readBuf.Length); + if(debug) + DataFile.WriteTo("ATA Report", "readdmaretrychs", "_debug_" + dev.Model + ".bin", "read results", + readBuf); + + DicConsole.WriteLine("Trying SEEK in CHS mode..."); + sense = dev.Seek(out errorChs, 0, 0, 1, dev.Timeout, out _); + capabilities.SupportsSeek = !sense && (errorChs.Status & 0x01) != 0x01 && errorChs.Error == 0; + DicConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}", sense, + errorChs.Status, errorChs.Error); + + DicConsole.WriteLine("Trying READ SECTOR(S) in LBA mode..."); + sense = dev.Read(out readBuf, out AtaErrorRegistersLba28 errorLba, false, 0, 1, dev.Timeout, out _); + capabilities.SupportsReadLba = + !sense && (errorLba.Status & 0x01) != 0x01 && errorLba.Error == 0 && readBuf.Length > 0; + DicConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", + sense, errorLba.Status, errorLba.Error, readBuf.Length); + if(debug) + DataFile.WriteTo("ATA Report", "readsectors", "_debug_" + dev.Model + ".bin", "read results", readBuf); + + DicConsole.WriteLine("Trying READ SECTOR(S) RETRY in LBA mode..."); + sense = dev.Read(out readBuf, out errorLba, true, 0, 1, dev.Timeout, out _); + capabilities.SupportsReadRetryLba = !sense && (errorLba.Status & 0x01) != 0x01 && errorLba.Error == 0 && + readBuf.Length > 0; + DicConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", + sense, errorLba.Status, errorLba.Error, readBuf.Length); + if(debug) + DataFile.WriteTo("ATA Report", "readsectorsretry", "_debug_" + dev.Model + ".bin", "read results", + readBuf); + + DicConsole.WriteLine("Trying READ DMA in LBA mode..."); + sense = dev.ReadDma(out readBuf, out errorLba, false, 0, 1, dev.Timeout, out _); + capabilities.SupportsReadDmaLba = !sense && (errorLba.Status & 0x01) != 0x01 && errorLba.Error == 0 && + readBuf.Length > 0; + DicConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", + sense, errorLba.Status, errorLba.Error, readBuf.Length); + if(debug) + DataFile.WriteTo("ATA Report", "readdma", "_debug_" + dev.Model + ".bin", "read results", readBuf); + + DicConsole.WriteLine("Trying READ DMA RETRY in LBA mode..."); + sense = dev.ReadDma(out readBuf, out errorLba, true, 0, 1, dev.Timeout, out _); + capabilities.SupportsReadDmaRetryLba = + !sense && (errorLba.Status & 0x01) != 0x01 && errorLba.Error == 0 && readBuf.Length > 0; + DicConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", + sense, errorLba.Status, errorLba.Error, readBuf.Length); + if(debug) + DataFile.WriteTo("ATA Report", "readdmaretry", "_debug_" + dev.Model + ".bin", "read results", readBuf); + + DicConsole.WriteLine("Trying SEEK in LBA mode..."); + sense = dev.Seek(out errorLba, 0, dev.Timeout, out _); + capabilities.SupportsSeekLba = !sense && (errorLba.Status & 0x01) != 0x01 && errorLba.Error == 0; + DicConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}", sense, + errorLba.Status, errorLba.Error); + + DicConsole.WriteLine("Trying READ SECTOR(S) in LBA48 mode..."); + sense = dev.Read(out readBuf, out AtaErrorRegistersLba48 errorLba48, 0, 1, dev.Timeout, out _); + capabilities.SupportsReadLba48 = !sense && (errorLba48.Status & 0x01) != 0x01 && errorLba48.Error == 0 && + readBuf.Length > 0; + DicConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", + sense, errorLba48.Status, errorLba48.Error, readBuf.Length); + if(debug) + DataFile.WriteTo("ATA Report", "readsectors48", "_debug_" + dev.Model + ".bin", "read results", + readBuf); + + DicConsole.WriteLine("Trying READ DMA in LBA48 mode..."); + sense = dev.ReadDma(out readBuf, out errorLba48, 0, 1, dev.Timeout, out _); + capabilities.SupportsReadDmaLba48 = !sense && (errorLba48.Status & 0x01) != 0x01 && errorLba48.Error == 0 && + readBuf.Length > 0; + DicConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", + sense, errorLba48.Status, errorLba48.Error, readBuf.Length); + if(debug) + DataFile.WriteTo("ATA Report", "readdma48", "_debug_" + dev.Model + ".bin", "read results", readBuf); + + // Send SET FEATURES before sending READ LONG commands, retrieve IDENTIFY again and + // check if ECC size changed. Sector is set to 1 because without it most drives just return + // CORRECTABLE ERROR for this command. + dev.SetFeatures(out _, AtaFeatures.EnableReadLongVendorLength, 0, 0, 1, 0, dev.Timeout, out _); + + dev.AtaIdentify(out byte[] buffer, out _, dev.Timeout, out _); + if(Identify.Decode(buffer).HasValue) + { + ataId = Identify.Decode(buffer).Value; + if(ataId.EccBytes != 0x0000 && ataId.EccBytes != 0xFFFF) + capabilities.LongBlockSize = logicalsectorsize + ataId.EccBytes; + + if(ataId.UnformattedBPS > logicalsectorsize && + (!(ataId.EccBytes != 0x0000 && ataId.EccBytes != 0xFFFF) || capabilities.LongBlockSize == 516)) + capabilities.LongBlockSize = ataId.UnformattedBPS; + } + + DicConsole.WriteLine("Trying READ LONG in CHS mode..."); + sense = dev.ReadLong(out readBuf, out errorChs, false, 0, 0, 1, capabilities.LongBlockSize ?? 0, + dev.Timeout, out _); + capabilities.SupportsReadLong = !sense && (errorChs.Status & 0x01) != 0x01 && + errorChs.Error == 0 && + readBuf.Length > 0 && + BitConverter.ToUInt64(readBuf, 0) != checkCorrectRead; + DicConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", + sense, errorChs.Status, errorChs.Error, readBuf.Length); + if(debug) + DataFile.WriteTo("ATA Report", "readlongchs", "_debug_" + dev.Model + ".bin", "read results", readBuf); + + DicConsole.WriteLine("Trying READ LONG RETRY in CHS mode..."); + sense = dev.ReadLong(out readBuf, out errorChs, true, 0, 0, 1, capabilities.LongBlockSize ?? 0, dev.Timeout, + out _); + capabilities.SupportsReadLongRetry = !sense && (errorChs.Status & 0x01) != 0x01 && errorChs.Error == 0 && + readBuf.Length > 0 && + BitConverter.ToUInt64(readBuf, 0) != + checkCorrectRead; + DicConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", + sense, errorChs.Status, errorChs.Error, readBuf.Length); + if(debug) + DataFile.WriteTo("ATA Report", "readlongretrychs", "_debug_" + dev.Model + ".bin", "read results", + readBuf); + + DicConsole.WriteLine("Trying READ LONG in LBA mode..."); + sense = dev.ReadLong(out readBuf, out errorLba, false, 0, capabilities.LongBlockSize ?? 0, dev.Timeout, + out _); + capabilities.SupportsReadLongLba = !sense && (errorLba.Status & 0x01) != 0x01 && errorLba.Error == 0 && + readBuf.Length > 0 && + BitConverter.ToUInt64(readBuf, 0) != checkCorrectRead; + DicConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", + sense, errorLba.Status, errorLba.Error, readBuf.Length); + if(debug) + DataFile.WriteTo("ATA Report", "readlong", "_debug_" + dev.Model + ".bin", "read results", readBuf); + + DicConsole.WriteLine("Trying READ LONG RETRY in LBA mode..."); + sense = dev.ReadLong(out readBuf, out errorLba, true, 0, capabilities.LongBlockSize ?? 0, dev.Timeout, + out _); + capabilities.SupportsReadLongRetryLba = !sense && (errorLba.Status & 0x01) != 0x01 && errorLba.Error == 0 && + readBuf.Length > 0 && + BitConverter.ToUInt64(readBuf, 0) != + checkCorrectRead; + DicConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", + sense, errorLba.Status, errorLba.Error, readBuf.Length); + if(debug) + DataFile.WriteTo("ATA Report", "readlongretry", "_debug_" + dev.Model + ".bin", "read results", + readBuf); + + return capabilities; } } } \ No newline at end of file diff --git a/DiscImageChef/Commands/DeviceReport.cs b/DiscImageChef/Commands/DeviceReport.cs index 99e8c7054..a59f66034 100644 --- a/DiscImageChef/Commands/DeviceReport.cs +++ b/DiscImageChef/Commands/DeviceReport.cs @@ -31,13 +31,14 @@ // ****************************************************************************/ using System; +using System.Collections.Generic; using System.IO; using DiscImageChef.CommonTypes.Metadata; using DiscImageChef.Console; using DiscImageChef.Core.Devices.Report.SCSI; +using DiscImageChef.Decoders.ATA; using DiscImageChef.Devices; using Newtonsoft.Json; -using Ata = DiscImageChef.Core.Devices.Report.Ata; namespace DiscImageChef.Commands { @@ -78,9 +79,11 @@ namespace DiscImageChef.Commands Core.Devices.Report.DeviceReport reporter = new Core.Devices.Report.DeviceReport(dev, options.Debug); + ConsoleKeyInfo pressedKey; + if(dev.IsUsb) { - ConsoleKeyInfo pressedKey = new ConsoleKeyInfo(); + pressedKey = new ConsoleKeyInfo(); while(pressedKey.Key != ConsoleKey.Y && pressedKey.Key != ConsoleKey.N) { DicConsole.Write("Is the device natively USB (in case of doubt, press Y)? (Y/N): "); @@ -107,7 +110,7 @@ namespace DiscImageChef.Commands if(dev.IsFireWire) { - ConsoleKeyInfo pressedKey = new ConsoleKeyInfo(); + pressedKey = new ConsoleKeyInfo(); while(pressedKey.Key != ConsoleKey.Y && pressedKey.Key != ConsoleKey.N) { DicConsole.Write("Is the device natively FireWire (in case of doubt, press Y)? (Y/N): "); @@ -137,8 +140,82 @@ namespace DiscImageChef.Commands switch(dev.Type) { case DeviceType.ATA: - Ata.Report(dev, ref report, options.Debug, ref removable); + { + DicConsole.WriteLine("Querying ATA IDENTIFY..."); + + dev.AtaIdentify(out byte[] buffer, out _, dev.Timeout, out _); + + if(!Identify.Decode(buffer).HasValue) break; + + report.ATA = new Ata {IdentifyDevice = Identify.Decode(buffer)}; + + if(report.ATA.IdentifyDevice == null) break; + + if((ushort)report.ATA.IdentifyDevice?.GeneralConfiguration == 0x848A) + { + report.CompactFlash = true; + removable = false; + } + else if(!removable && + report.ATA.IdentifyDevice?.GeneralConfiguration.HasFlag(Identify.GeneralConfigurationBit + .Removable) == true) + { + pressedKey = new ConsoleKeyInfo(); + while(pressedKey.Key != ConsoleKey.Y && pressedKey.Key != ConsoleKey.N) + { + DicConsole.Write("Is the media removable from the reading/writing elements? (Y/N): "); + pressedKey = System.Console.ReadKey(); + DicConsole.WriteLine(); + } + + removable = pressedKey.Key == ConsoleKey.Y; + } + + if(removable) + { + DicConsole + .WriteLine("Please remove any media from the device and press any key when it is out."); + System.Console.ReadKey(true); + DicConsole.WriteLine("Querying ATA IDENTIFY..."); + dev.AtaIdentify(out buffer, out _, dev.Timeout, out _); + report.ATA.IdentifyDevice = Identify.Decode(buffer); + if(options.Debug) report.ATA.Identify = buffer; + List mediaTests = new List(); + + pressedKey = new ConsoleKeyInfo(); + while(pressedKey.Key != ConsoleKey.N) + { + pressedKey = new ConsoleKeyInfo(); + while(pressedKey.Key != ConsoleKey.Y && pressedKey.Key != ConsoleKey.N) + { + DicConsole.Write("Do you have media that you can insert in the drive? (Y/N): "); + pressedKey = System.Console.ReadKey(); + DicConsole.WriteLine(); + } + + if(pressedKey.Key != ConsoleKey.Y) continue; + + DicConsole.WriteLine("Please insert it in the drive and press any key when it is ready."); + System.Console.ReadKey(true); + + DicConsole.Write("Please write a description of the media type and press enter: "); + string mediumTypeName = System.Console.ReadLine(); + DicConsole.Write("Please write the media model and press enter: "); + string mediumModel = System.Console.ReadLine(); + + TestedMedia mediaTest = reporter.ReportAtaMedia(); + mediaTest.MediumTypeName = mediumTypeName; + mediaTest.Model = mediumModel; + + mediaTests.Add(mediaTest); + } + + report.ATA.RemovableMedias = mediaTests.ToArray(); + } + else report.ATA.ReadCapabilities = reporter.ReportAta(report.ATA.IdentifyDevice.Value); + break; + } case DeviceType.MMC: report.MultiMediaCard = reporter.MmcSdReport(); break; @@ -147,8 +224,6 @@ namespace DiscImageChef.Commands break; case DeviceType.NVMe: throw new NotImplementedException("NVMe devices not yet supported."); - - break; case DeviceType.ATAPI: case DeviceType.SCSI: General.Report(dev, ref report, options.Debug, ref removable);