From 745e408233dac4979425440a640ccbfcab72caaf Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Sun, 25 Nov 2018 20:08:28 +0000 Subject: [PATCH] Move SCSI device reporting to non-static class and its UI to CLI. --- .../Devices/Report/SCSI/General.cs | 1063 ++++++----------- DiscImageChef.Core/Devices/Report/SCSI/MMC.cs | 6 +- DiscImageChef.Core/Devices/Report/SCSI/SSC.cs | 4 +- DiscImageChef/Commands/DeviceReport.cs | 261 +++- 4 files changed, 653 insertions(+), 681 deletions(-) diff --git a/DiscImageChef.Core/Devices/Report/SCSI/General.cs b/DiscImageChef.Core/Devices/Report/SCSI/General.cs index 386273906..eeaf495b6 100644 --- a/DiscImageChef.Core/Devices/Report/SCSI/General.cs +++ b/DiscImageChef.Core/Devices/Report/SCSI/General.cs @@ -32,115 +32,69 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; -using System.Threading; using DiscImageChef.CommonTypes.Metadata; using DiscImageChef.Console; using DiscImageChef.Decoders.SCSI; using DiscImageChef.Devices; -namespace DiscImageChef.Core.Devices.Report.SCSI +namespace DiscImageChef.Core.Devices.Report { - /// - /// Implements creating a report of SCSI and ATAPI devices - /// - public static class General + public partial class DeviceReport { - /// - /// Creates a report of SCSI and ATAPI devices, and if appropiate calls the report creators for MultiMedia and - /// Streaming devices - /// - /// 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 Scsi ReportScsiInquiry() { - if(report == null) return; - - bool sense; - const uint TIMEOUT = 5; - ConsoleKeyInfo pressedKey; - - if(!dev.IsUsb && !dev.IsFireWire && dev.IsRemovable) - { - pressedKey = new ConsoleKeyInfo(); - while(pressedKey.Key != ConsoleKey.Y && pressedKey.Key != ConsoleKey.N) - { - DicConsole.Write("Is the media removable from the reading/writing elements (flash memories ARE NOT removable)? (Y/N): "); - pressedKey = System.Console.ReadKey(); - DicConsole.WriteLine(); - } - - removable = pressedKey.Key == ConsoleKey.Y; - } - DicConsole.WriteLine("Querying SCSI INQUIRY..."); - sense = dev.ScsiInquiry(out byte[] buffer, out byte[] senseBuffer); + bool sense = dev.ScsiInquiry(out byte[] buffer, out byte[] senseBuffer); - report.SCSI = new Scsi(); + Scsi report = new Scsi(); - if(!sense && Inquiry.Decode(buffer).HasValue) - { - report.SCSI.Inquiry = Inquiry.Decode(buffer); + if(sense || !Inquiry.Decode(buffer).HasValue) return null; - if(debug) report.SCSI.InquiryData = buffer; - } + report.Inquiry = Inquiry.Decode(buffer); + if(debug) report.InquiryData = buffer; + + return report; + } + + public ScsiPage[] ReportEvpdPages() + { DicConsole.WriteLine("Querying list of SCSI EVPDs..."); - sense = dev.ScsiInquiry(out buffer, out senseBuffer, 0x00); + bool sense = dev.ScsiInquiry(out byte[] buffer, out _, 0x00); - if(!sense) + if(sense) return null; + + byte[] evpdPages = EVPD.DecodePage00(buffer); + if(evpdPages == null || evpdPages.Length <= 0) return null; + + List evpds = new List(); + foreach(byte page in evpdPages.Where(page => page != 0x80)) { - byte[] evpdPages = EVPD.DecodePage00(buffer); - if(evpdPages != null && evpdPages.Length > 0) - { - List evpds = new List(); - foreach(byte page in evpdPages.Where(page => page != 0x80)) - { - DicConsole.WriteLine("Querying SCSI EVPD {0:X2}h...", page); - sense = dev.ScsiInquiry(out buffer, out senseBuffer, page); - if(sense) continue; + DicConsole.WriteLine("Querying SCSI EVPD {0:X2}h...", page); + sense = dev.ScsiInquiry(out buffer, out _, page); + if(sense) continue; - ScsiPage evpd = new ScsiPage {page = page, value = buffer}; - evpds.Add(evpd); - } - - if(evpds.Count > 0) report.SCSI.EVPDPages = evpds.ToArray(); - } + ScsiPage evpd = new ScsiPage {page = page, value = buffer}; + evpds.Add(evpd); } - if(removable) - { - switch(dev.ScsiType) - { - case PeripheralDeviceTypes.MultiMediaDevice: - dev.AllowMediumRemoval(out senseBuffer, TIMEOUT, out _); - dev.EjectTray(out senseBuffer, TIMEOUT, out _); - break; - case PeripheralDeviceTypes.SequentialAccess: - dev.SpcAllowMediumRemoval(out senseBuffer, TIMEOUT, out _); - DicConsole.WriteLine("Asking drive to unload tape (can take a few minutes)..."); - dev.Unload(out senseBuffer, TIMEOUT, out _); - break; - } - - DicConsole.WriteLine("Please remove any media from the device and press any key when it is out."); - System.Console.ReadKey(true); - } + return evpds.Count > 0 ? evpds.ToArray() : null; + } + public void ReportScsiModes(ref DeviceReportV2 report, ref Modes.ModePage_2A? cdromMode) + { Modes.DecodedMode? decMode = null; PeripheralDeviceTypes devType = dev.ScsiType; DicConsole.WriteLine("Querying all mode pages and subpages using SCSI MODE SENSE (10)..."); - sense = dev.ModeSense10(out byte[] mode10Buffer, out senseBuffer, false, true, - ScsiModeSensePageControl.Default, 0x3F, 0xFF, TIMEOUT, out _); + bool sense = dev.ModeSense10(out byte[] mode10Buffer, out _, false, true, ScsiModeSensePageControl.Default, + 0x3F, 0xFF, dev.Timeout, out _); if(sense || dev.Error) { DicConsole.WriteLine("Querying all mode pages using SCSI MODE SENSE (10)..."); - sense = dev.ModeSense10(out mode10Buffer, out senseBuffer, false, true, - ScsiModeSensePageControl.Default, 0x3F, 0x00, TIMEOUT, out _); + sense = dev.ModeSense10(out mode10Buffer, out _, false, true, ScsiModeSensePageControl.Default, 0x3F, + 0x00, dev.Timeout, out _); if(!sense && !dev.Error) { report.SCSI.SupportsModeSense10 = true; @@ -156,17 +110,17 @@ namespace DiscImageChef.Core.Devices.Report.SCSI } DicConsole.WriteLine("Querying all mode pages and subpages using SCSI MODE SENSE (6)..."); - sense = dev.ModeSense6(out byte[] mode6Buffer, out senseBuffer, false, ScsiModeSensePageControl.Default, - 0x3F, 0xFF, TIMEOUT, out _); + sense = dev.ModeSense6(out byte[] mode6Buffer, out _, false, ScsiModeSensePageControl.Default, 0x3F, 0xFF, + dev.Timeout, out _); if(sense || dev.Error) { DicConsole.WriteLine("Querying all mode pages using SCSI MODE SENSE (6)..."); - sense = dev.ModeSense6(out mode6Buffer, out senseBuffer, false, ScsiModeSensePageControl.Default, 0x3F, - 0x00, TIMEOUT, out _); + sense = dev.ModeSense6(out mode6Buffer, out _, false, ScsiModeSensePageControl.Default, 0x3F, 0x00, + dev.Timeout, out _); if(sense || dev.Error) { DicConsole.WriteLine("Querying SCSI MODE SENSE (6)..."); - sense = dev.ModeSense(out mode6Buffer, out senseBuffer, TIMEOUT, out _); + sense = dev.ModeSense(out mode6Buffer, out _, dev.Timeout, out _); } } else report.SCSI.SupportsModeSubpages = true; @@ -175,604 +129,371 @@ namespace DiscImageChef.Core.Devices.Report.SCSI report.SCSI.SupportsModeSense6 |= !sense && !dev.Error; - Modes.ModePage_2A? cdromMode = null; + cdromMode = null; if(debug && report.SCSI.SupportsModeSense6) report.SCSI.ModeSense6Data = mode6Buffer; if(debug && report.SCSI.SupportsModeSense10) report.SCSI.ModeSense10Data = mode10Buffer; + if(!decMode.HasValue) return; + + report.SCSI.ModeSense = new ScsiMode + { + BlankCheckEnabled = decMode.Value.Header.EBC, + DPOandFUA = decMode.Value.Header.DPOFUA, + WriteProtected = decMode.Value.Header.WriteProtected + }; + + if(decMode.Value.Header.BufferedMode > 0) + report.SCSI.ModeSense.BufferedMode = decMode.Value.Header.BufferedMode; + + if(decMode.Value.Header.Speed > 0) report.SCSI.ModeSense.Speed = decMode.Value.Header.Speed; + + if(decMode.Value.Pages == null) return; + + List modePages = new List(); + foreach(Modes.ModePage page in decMode.Value.Pages) + { + ScsiPage modePage = new ScsiPage {page = page.Page, subpage = page.Subpage, value = page.PageResponse}; + modePages.Add(modePage); + + if(modePage.page == 0x2A && modePage.subpage == 0x00) + cdromMode = Modes.DecodeModePage_2A(page.PageResponse); + } + + if(modePages.Count > 0) report.SCSI.ModeSense.ModePages = modePages.ToArray(); + } + + public TestedMedia ReportScsiMedia() + { + TestedMedia mediaTest = new TestedMedia(); + DicConsole.WriteLine("Querying SCSI READ CAPACITY..."); + bool sense = dev.ReadCapacity(out byte[] buffer, out byte[] senseBuffer, dev.Timeout, out _); + if(!sense && !dev.Error) + { + mediaTest.SupportsReadCapacity = true; + mediaTest.Blocks = + (ulong)((buffer[0] << 24) + (buffer[1] << 16) + (buffer[2] << 8) + buffer[3]) + 1; + mediaTest.BlockSize = + (uint)((buffer[4] << 24) + (buffer[5] << 16) + (buffer[6] << 8) + buffer[7]); + } + + DicConsole.WriteLine("Querying SCSI READ CAPACITY (16)..."); + sense = dev.ReadCapacity16(out buffer, out buffer, dev.Timeout, out _); + if(!sense && !dev.Error) + { + mediaTest.SupportsReadCapacity16 = true; + byte[] temp = new byte[8]; + Array.Copy(buffer, 0, temp, 0, 8); + Array.Reverse(temp); + mediaTest.Blocks = BitConverter.ToUInt64(temp, 0) + 1; + mediaTest.BlockSize = (uint)((buffer[8] << 24) + (buffer[9] << 16) + (buffer[10] << 8) + buffer[11]); + } + + Modes.DecodedMode? decMode = null; + + DicConsole.WriteLine("Querying SCSI MODE SENSE (10)..."); + sense = dev.ModeSense10(out buffer, out senseBuffer, false, true, ScsiModeSensePageControl.Current, 0x3F, + 0x00, dev.Timeout, out _); + if(!sense && !dev.Error) + { + decMode = Modes.DecodeMode10(buffer, dev.ScsiType); + if(debug) mediaTest.ModeSense10Data = buffer; + } + + DicConsole.WriteLine("Querying SCSI MODE SENSE..."); + sense = dev.ModeSense(out buffer, out senseBuffer, dev.Timeout, out _); + if(!sense && !dev.Error) + { + if(!decMode.HasValue) decMode = Modes.DecodeMode6(buffer, dev.ScsiType); + if(debug) mediaTest.ModeSense6Data = buffer; + } + if(decMode.HasValue) { - report.SCSI.ModeSense = new ScsiMode - { - BlankCheckEnabled = decMode.Value.Header.EBC, - DPOandFUA = decMode.Value.Header.DPOFUA, - WriteProtected = decMode.Value.Header.WriteProtected - }; - - if(decMode.Value.Header.BufferedMode > 0) - report.SCSI.ModeSense.BufferedMode = decMode.Value.Header.BufferedMode; - - if(decMode.Value.Header.Speed > 0) report.SCSI.ModeSense.Speed = decMode.Value.Header.Speed; - - if(decMode.Value.Pages != null) - { - List modePages = new List(); - foreach(Modes.ModePage page in decMode.Value.Pages) - { - ScsiPage modePage = new ScsiPage - { - page = page.Page, subpage = page.Subpage, value = page.PageResponse - }; - modePages.Add(modePage); - - if(modePage.page == 0x2A && modePage.subpage == 0x00) - cdromMode = Modes.DecodeModePage_2A(page.PageResponse); - } - - if(modePages.Count > 0) report.SCSI.ModeSense.ModePages = modePages.ToArray(); - } + mediaTest.MediumType = (byte)decMode.Value.Header.MediumType; + if(decMode.Value.Header.BlockDescriptors != null && decMode.Value.Header.BlockDescriptors.Length > 0) + mediaTest.Density = (byte)decMode.Value.Header.BlockDescriptors[0].Density; } - string productIdentification = null; - if(!string.IsNullOrWhiteSpace(StringHandlers.CToString(report.SCSI.Inquiry?.ProductIdentification))) - productIdentification = StringHandlers.CToString(report.SCSI.Inquiry?.ProductIdentification).Trim(); + DicConsole.WriteLine("Trying SCSI READ (6)..."); + mediaTest.SupportsRead6 = !dev.Read6(out buffer, out senseBuffer, 0, + mediaTest.BlockSize ?? 512, dev.Timeout, out _); + DicConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.SupportsRead6); + if(debug) + DataFile.WriteTo("SCSI Report", "read6", "_debug_" + mediaTest.MediumTypeName + ".bin", "read results", + buffer); - switch(dev.ScsiType) + DicConsole.WriteLine("Trying SCSI READ (10)..."); + mediaTest.SupportsRead10 = !dev.Read10(out buffer, out senseBuffer, 0, false, true, false, false, 0, + mediaTest.BlockSize ?? 512, 0, 1, dev.Timeout, out _); + DicConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.SupportsRead10); + if(debug) + DataFile.WriteTo("SCSI Report", "read10", "_debug_" + mediaTest.MediumTypeName + ".bin", "read results", + buffer); + + DicConsole.WriteLine("Trying SCSI READ (12)..."); + mediaTest.SupportsRead12 = !dev.Read12(out buffer, out senseBuffer, 0, false, true, false, false, 0, + mediaTest.BlockSize ?? 512, 0, 1, false, dev.Timeout, out _); + DicConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.SupportsRead12); + if(debug) + DataFile.WriteTo("SCSI Report", "read12", "_debug_" + mediaTest.MediumTypeName + ".bin", "read results", + buffer); + + DicConsole.WriteLine("Trying SCSI READ (16)..."); + mediaTest.SupportsRead16 = !dev.Read16(out buffer, out senseBuffer, 0, false, true, false, 0, + mediaTest.BlockSize ?? 512, 0, 1, false, dev.Timeout, out _); + DicConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.SupportsRead16); + if(debug) + DataFile.WriteTo("SCSI Report", "read16", "_debug_" + mediaTest.MediumTypeName + ".bin", "read results", + buffer); + + mediaTest.LongBlockSize = mediaTest.BlockSize; + DicConsole.WriteLine("Trying SCSI READ LONG (10)..."); + sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, 0xFFFF, dev.Timeout, out _); + if(sense && !dev.Error) { - case PeripheralDeviceTypes.MultiMediaDevice: - Mmc.Report(dev, ref report, debug, ref cdromMode, productIdentification); - break; - case PeripheralDeviceTypes.SequentialAccess: - Ssc.Report(dev, ref report, debug); - break; - default: - if(removable) + FixedSense? decSense = Sense.DecodeFixed(senseBuffer); + if(decSense.HasValue) + if(decSense.Value.SenseKey == SenseKeys.IllegalRequest && decSense.Value.ASC == 0x24 && + decSense.Value.ASCQ == 0x00) { - 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 manufacturer and press enter: "); - mediaTest.Manufacturer = System.Console.ReadLine(); - DicConsole.Write("Please write the media model and press enter: "); - mediaTest.Model = System.Console.ReadLine(); - - mediaTest.MediaIsRecognized = true; - - sense = dev.ScsiTestUnitReady(out senseBuffer, TIMEOUT, out _); - if(sense) - { - FixedSense? decSense = Sense.DecodeFixed(senseBuffer); - if(decSense.HasValue) - if(decSense.Value.ASC == 0x3A) - { - int leftRetries = 20; - while(leftRetries > 0) - { - DicConsole.Write("\rWaiting for drive to become ready"); - Thread.Sleep(2000); - sense = dev.ScsiTestUnitReady(out senseBuffer, TIMEOUT, out _); - if(!sense) break; - - leftRetries--; - } - - mediaTest.MediaIsRecognized &= !sense; - } - else if(decSense.Value.ASC == 0x04 && decSense.Value.ASCQ == 0x01) - { - int leftRetries = 20; - while(leftRetries > 0) - { - DicConsole.Write("\rWaiting for drive to become ready"); - Thread.Sleep(2000); - sense = dev.ScsiTestUnitReady(out senseBuffer, TIMEOUT, out _); - if(!sense) break; - - leftRetries--; - } - - mediaTest.MediaIsRecognized &= !sense; - } - else mediaTest.MediaIsRecognized = false; - else mediaTest.MediaIsRecognized = false; - } - - if(mediaTest.MediaIsRecognized) - { - DicConsole.WriteLine("Querying SCSI READ CAPACITY..."); - sense = dev.ReadCapacity(out buffer, out senseBuffer, TIMEOUT, out _); - if(!sense && !dev.Error) - { - mediaTest.SupportsReadCapacity = true; - mediaTest.Blocks = - (ulong)((buffer[0] << 24) + (buffer[1] << 16) + (buffer[2] << 8) + buffer[3]) + - 1; - mediaTest.BlockSize = - (uint)((buffer[4] << 24) + (buffer[5] << 16) + (buffer[6] << 8) + buffer[7]); - } - - DicConsole.WriteLine("Querying SCSI READ CAPACITY (16)..."); - sense = dev.ReadCapacity16(out buffer, out buffer, TIMEOUT, out _); - if(!sense && !dev.Error) - { - mediaTest.SupportsReadCapacity16 = true; - byte[] temp = new byte[8]; - Array.Copy(buffer, 0, temp, 0, 8); - Array.Reverse(temp); - mediaTest.Blocks = BitConverter.ToUInt64(temp, 0) + 1; - mediaTest.BlockSize = - (uint)((buffer[8] << 24) + (buffer[9] << 16) + (buffer[10] << 8) + buffer[11]); - } - - decMode = null; - - DicConsole.WriteLine("Querying SCSI MODE SENSE (10)..."); - sense = dev.ModeSense10(out buffer, out senseBuffer, false, true, - ScsiModeSensePageControl.Current, 0x3F, 0x00, TIMEOUT, out _); - if(!sense && !dev.Error) - { - report.SCSI.SupportsModeSense10 = true; - decMode = Modes.DecodeMode10(buffer, dev.ScsiType); - if(debug) mediaTest.ModeSense10Data = buffer; - } - - DicConsole.WriteLine("Querying SCSI MODE SENSE..."); - sense = dev.ModeSense(out buffer, out senseBuffer, TIMEOUT, out _); - if(!sense && !dev.Error) - { - report.SCSI.SupportsModeSense6 = true; - if(!decMode.HasValue) decMode = Modes.DecodeMode6(buffer, dev.ScsiType); - if(debug) mediaTest.ModeSense6Data = buffer; - } - - if(decMode.HasValue) - { - mediaTest.MediumType = (byte)decMode.Value.Header.MediumType; - if(decMode.Value.Header.BlockDescriptors != null && - decMode.Value.Header.BlockDescriptors.Length > 0) - mediaTest.Density = (byte)decMode.Value.Header.BlockDescriptors[0].Density; - } - - DicConsole.WriteLine("Trying SCSI READ (6)..."); - mediaTest.SupportsRead6 = !dev.Read6(out buffer, out senseBuffer, 0, - mediaTest.BlockSize ?? 512, TIMEOUT, out _); - DicConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.SupportsRead6); - if(debug) - DataFile.WriteTo("SCSI Report", "read6", - "_debug_" + mediaTest.MediumTypeName + ".bin", "read results", - buffer); - - DicConsole.WriteLine("Trying SCSI READ (10)..."); - mediaTest.SupportsRead10 = - !dev.Read10(out buffer, out senseBuffer, 0, false, true, false, false, 0, - mediaTest.BlockSize ?? 512, 0, 1, TIMEOUT, out _); - DicConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.SupportsRead10); - if(debug) - DataFile.WriteTo("SCSI Report", "read10", - "_debug_" + mediaTest.MediumTypeName + ".bin", "read results", - buffer); - - DicConsole.WriteLine("Trying SCSI READ (12)..."); - mediaTest.SupportsRead12 = - !dev.Read12(out buffer, out senseBuffer, 0, false, true, false, false, 0, - mediaTest.BlockSize ?? 512, 0, 1, false, TIMEOUT, out _); - DicConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.SupportsRead12); - if(debug) - DataFile.WriteTo("SCSI Report", "read12", - "_debug_" + mediaTest.MediumTypeName + ".bin", "read results", - buffer); - - DicConsole.WriteLine("Trying SCSI READ (16)..."); - mediaTest.SupportsRead16 = - !dev.Read16(out buffer, out senseBuffer, 0, false, true, false, 0, - mediaTest.BlockSize ?? 512, 0, 1, false, TIMEOUT, out _); - DicConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.SupportsRead16); - if(debug) - DataFile.WriteTo("SCSI Report", "read16", - "_debug_" + mediaTest.MediumTypeName + ".bin", "read results", - buffer); - - mediaTest.LongBlockSize = mediaTest.BlockSize; - DicConsole.WriteLine("Trying SCSI READ LONG (10)..."); - sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, 0xFFFF, TIMEOUT, - out _); - if(sense && !dev.Error) - { - FixedSense? decSense = Sense.DecodeFixed(senseBuffer); - if(decSense.HasValue) - if(decSense.Value.SenseKey == SenseKeys.IllegalRequest && - decSense.Value.ASC == 0x24 && - decSense.Value.ASCQ == 0x00) - { - mediaTest.SupportsReadLong = true; - if(decSense.Value.InformationValid && decSense.Value.ILI) - mediaTest.LongBlockSize = - 0xFFFF - (decSense.Value.Information & 0xFFFF); - } - } - - if(mediaTest.SupportsReadLong == true && mediaTest.LongBlockSize == mediaTest.BlockSize) - if(mediaTest.BlockSize == 512) - foreach(int i in new[] - { - // Long sector sizes for floppies - 514, - // Long sector sizes for SuperDisk - 536, 558, - // Long sector sizes for 512-byte magneto-opticals - 600, 610, 630 - }) - { - ushort testSize = (ushort)i; - sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, - testSize, TIMEOUT, out _); - if(sense || dev.Error) continue; - - mediaTest.SupportsReadLong = true; - mediaTest.LongBlockSize = testSize; - break; - } - else if(mediaTest.BlockSize == 1024) - foreach(int i in new[] - { - // Long sector sizes for floppies - 1026, - // Long sector sizes for 1024-byte magneto-opticals - 1200 - }) - { - ushort testSize = (ushort)i; - sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, - (ushort)i, TIMEOUT, out _); - if(sense || dev.Error) continue; - - mediaTest.SupportsReadLong = true; - mediaTest.LongBlockSize = testSize; - break; - } - else if(mediaTest.BlockSize == 2048) - { - sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, 2380, - TIMEOUT, out _); - if(!sense && !dev.Error) - { - mediaTest.SupportsReadLong = true; - mediaTest.LongBlockSize = 2380; - } - } - else if(mediaTest.BlockSize == 4096) - { - sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, 4760, - TIMEOUT, out _); - if(!sense && !dev.Error) - { - mediaTest.SupportsReadLong = true; - mediaTest.LongBlockSize = 4760; - } - } - else if(mediaTest.BlockSize == 8192) - { - sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, 9424, - TIMEOUT, out _); - if(!sense && !dev.Error) - { - mediaTest.SupportsReadLong = true; - mediaTest.LongBlockSize = 9424; - } - } - - if(mediaTest.SupportsReadLong == true && mediaTest.LongBlockSize == mediaTest.BlockSize) - { - pressedKey = new ConsoleKeyInfo(); - while(pressedKey.Key != ConsoleKey.Y && pressedKey.Key != ConsoleKey.N) - { - DicConsole - .Write("Drive supports SCSI READ LONG but I cannot find the correct size. Do you want me to try? (This can take hours) (Y/N): "); - pressedKey = System.Console.ReadKey(); - DicConsole.WriteLine(); - } - - if(pressedKey.Key == ConsoleKey.Y) - { - for(ushort i = (ushort)mediaTest.BlockSize;; i++) - { - DicConsole.Write("\rTrying to READ LONG with a size of {0} bytes...", i); - sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, i, - TIMEOUT, out _); - if(!sense) - { - mediaTest.LongBlockSize = i; - break; - } - - if(i == ushort.MaxValue) break; - } - - DicConsole.WriteLine(); - } - } - - if(debug && mediaTest.SupportsReadLong == true && - mediaTest.LongBlockSize != mediaTest.BlockSize) - { - sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, - (ushort)mediaTest.LongBlockSize, TIMEOUT, out _); - if(!sense) - DataFile.WriteTo("SCSI Report", "readlong10", - "_debug_" + mediaTest.MediumTypeName + ".bin", "read results", - buffer); - } - - DicConsole.WriteLine("Trying SCSI READ MEDIA SERIAL NUMBER..."); - mediaTest.CanReadMediaSerial = - !dev.ReadMediaSerialNumber(out buffer, out senseBuffer, TIMEOUT, out _); - } - - mediaTests.Add(mediaTest); - } - - report.SCSI.RemovableMedias = mediaTests.ToArray(); + mediaTest.SupportsReadLong = true; + if(decSense.Value.InformationValid && decSense.Value.ILI) + mediaTest.LongBlockSize = 0xFFFF - (decSense.Value.Information & 0xFFFF); } - else - { - report.SCSI.ReadCapabilities = new TestedMedia(); - report.SCSI.ReadCapabilities.MediaIsRecognized = true; - - DicConsole.WriteLine("Querying SCSI READ CAPACITY..."); - sense = dev.ReadCapacity(out buffer, out senseBuffer, TIMEOUT, out _); - if(!sense && !dev.Error) - { - report.SCSI.ReadCapabilities.SupportsReadCapacity = true; - report.SCSI.ReadCapabilities.Blocks = - (ulong)((buffer[0] << 24) + (buffer[1] << 16) + (buffer[2] << 8) + buffer[3]) + 1; - report.SCSI.ReadCapabilities.BlockSize = - (uint)((buffer[4] << 24) + (buffer[5] << 16) + (buffer[6] << 8) + buffer[7]); - } - - DicConsole.WriteLine("Querying SCSI READ CAPACITY (16)..."); - sense = dev.ReadCapacity16(out buffer, out buffer, TIMEOUT, out _); - if(!sense && !dev.Error) - { - report.SCSI.ReadCapabilities.SupportsReadCapacity16 = true; - byte[] temp = new byte[8]; - Array.Copy(buffer, 0, temp, 0, 8); - Array.Reverse(temp); - report.SCSI.ReadCapabilities.Blocks = BitConverter.ToUInt64(temp, 0) + 1; - report.SCSI.ReadCapabilities.BlockSize = - (uint)((buffer[8] << 24) + (buffer[9] << 16) + (buffer[10] << 8) + buffer[11]); - } - - decMode = null; - - DicConsole.WriteLine("Querying SCSI MODE SENSE (10)..."); - sense = dev.ModeSense10(out buffer, out senseBuffer, false, true, - ScsiModeSensePageControl.Current, 0x3F, 0x00, TIMEOUT, out _); - if(!sense && !dev.Error) - { - report.SCSI.SupportsModeSense10 = true; - decMode = Modes.DecodeMode10(buffer, dev.ScsiType); - if(debug) report.SCSI.ReadCapabilities.ModeSense10Data = buffer; - } - - DicConsole.WriteLine("Querying SCSI MODE SENSE..."); - sense = dev.ModeSense(out buffer, out senseBuffer, TIMEOUT, out _); - if(!sense && !dev.Error) - { - report.SCSI.SupportsModeSense6 = true; - if(!decMode.HasValue) - decMode = Modes.DecodeMode6(buffer, dev.ScsiType); - if(debug) report.SCSI.ReadCapabilities.ModeSense6Data = buffer; - } - - if(decMode.HasValue) - { - report.SCSI.ReadCapabilities.MediumType = (byte)decMode.Value.Header.MediumType; - if(decMode.Value.Header.BlockDescriptors != null && - decMode.Value.Header.BlockDescriptors.Length > 0) - report.SCSI.ReadCapabilities.Density = - (byte)decMode.Value.Header.BlockDescriptors[0].Density; - } - - DicConsole.WriteLine("Trying SCSI READ (6)..."); - report.SCSI.ReadCapabilities.SupportsRead6 = - !dev.Read6(out buffer, out senseBuffer, 0, report.SCSI.ReadCapabilities.BlockSize ?? 512, - TIMEOUT, out _); - DicConsole.DebugWriteLine("SCSI Report", "Sense = {0}", - !report.SCSI.ReadCapabilities.SupportsRead6); - if(debug) - DataFile.WriteTo("SCSI Report", "read6", "_debug_" + productIdentification + ".bin", - "read results", buffer); - - DicConsole.WriteLine("Trying SCSI READ (10)..."); - report.SCSI.ReadCapabilities.SupportsRead10 = - !dev.Read10(out buffer, out senseBuffer, 0, false, true, false, false, 0, - report.SCSI.ReadCapabilities.BlockSize ?? 512, 0, 1, TIMEOUT, out _); - DicConsole.DebugWriteLine("SCSI Report", "Sense = {0}", - !report.SCSI.ReadCapabilities.SupportsRead10); - if(debug) - DataFile.WriteTo("SCSI Report", "read10", "_debug_" + productIdentification + ".bin", - "read results", buffer); - - DicConsole.WriteLine("Trying SCSI READ (12)..."); - report.SCSI.ReadCapabilities.SupportsRead12 = - !dev.Read12(out buffer, out senseBuffer, 0, false, true, false, false, 0, - report.SCSI.ReadCapabilities.BlockSize ?? 512, 0, 1, false, TIMEOUT, out _); - DicConsole.DebugWriteLine("SCSI Report", "Sense = {0}", - !report.SCSI.ReadCapabilities.SupportsRead12); - if(debug) - DataFile.WriteTo("SCSI Report", "read12", "_debug_" + productIdentification + ".bin", - "read results", buffer); - - DicConsole.WriteLine("Trying SCSI READ (16)..."); - report.SCSI.ReadCapabilities.SupportsRead16 = - !dev.Read16(out buffer, out senseBuffer, 0, false, true, false, 0, - report.SCSI.ReadCapabilities.BlockSize ?? 512, 0, 1, false, TIMEOUT, out _); - DicConsole.DebugWriteLine("SCSI Report", "Sense = {0}", - !report.SCSI.ReadCapabilities.SupportsRead16); - if(debug) - DataFile.WriteTo("SCSI Report", "read16", "_debug_" + productIdentification + ".bin", - "read results", buffer); - - report.SCSI.ReadCapabilities.LongBlockSize = report.SCSI.ReadCapabilities.BlockSize; - DicConsole.WriteLine("Trying SCSI READ LONG (10)..."); - sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, 0xFFFF, TIMEOUT, out _); - if(sense && !dev.Error) - { - FixedSense? decSense = Sense.DecodeFixed(senseBuffer); - if(decSense.HasValue) - if(decSense.Value.SenseKey == SenseKeys.IllegalRequest && decSense.Value.ASC == 0x24 && - decSense.Value.ASCQ == 0x00) - { - report.SCSI.ReadCapabilities.SupportsReadLong = true; - if(decSense.Value.InformationValid && decSense.Value.ILI) - report.SCSI.ReadCapabilities.LongBlockSize = - 0xFFFF - (decSense.Value.Information & 0xFFFF); - } - } - - if(report.SCSI.ReadCapabilities.SupportsReadLong == true && - report.SCSI.ReadCapabilities.LongBlockSize == report.SCSI.ReadCapabilities.BlockSize) - if(report.SCSI.ReadCapabilities.BlockSize == 512) - foreach(int i in new[] - { - // Long sector sizes for floppies - 514, - // Long sector sizes for SuperDisk - 536, 558, - // Long sector sizes for 512-byte magneto-opticals - 600, 610, 630 - }) - { - ushort testSize = (ushort)i; - sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, (ushort)i, - TIMEOUT, out _); - if(sense || dev.Error) continue; - - report.SCSI.ReadCapabilities.SupportsReadLong = true; - report.SCSI.ReadCapabilities.LongBlockSize = testSize; - break; - } - else if(report.SCSI.ReadCapabilities.BlockSize == 1024) - foreach(int i in new[] - { - // Long sector sizes for floppies - 1026, - // Long sector sizes for 1024-byte magneto-opticals - 1200 - }) - { - ushort testSize = (ushort)i; - sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, (ushort)i, - TIMEOUT, out _); - if(sense || dev.Error) continue; - - report.SCSI.ReadCapabilities.SupportsReadLong = true; - report.SCSI.ReadCapabilities.LongBlockSize = testSize; - break; - } - else if(report.SCSI.ReadCapabilities.BlockSize == 2048) - { - sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, 2380, TIMEOUT, - out _); - if(!sense && !dev.Error) - { - report.SCSI.ReadCapabilities.SupportsReadLong = true; - report.SCSI.ReadCapabilities.LongBlockSize = 2380; - } - } - else if(report.SCSI.ReadCapabilities.BlockSize == 4096) - { - sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, 4760, TIMEOUT, - out _); - if(!sense && !dev.Error) - { - report.SCSI.ReadCapabilities.SupportsReadLong = true; - report.SCSI.ReadCapabilities.LongBlockSize = 4760; - } - } - else if(report.SCSI.ReadCapabilities.BlockSize == 8192) - { - sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, 9424, TIMEOUT, - out _); - if(!sense && !dev.Error) - { - report.SCSI.ReadCapabilities.SupportsReadLong = true; - report.SCSI.ReadCapabilities.LongBlockSize = 9424; - } - } - - if(report.SCSI.ReadCapabilities.SupportsReadLong == true && - report.SCSI.ReadCapabilities.LongBlockSize == report.SCSI.ReadCapabilities.BlockSize) - { - pressedKey = new ConsoleKeyInfo(); - while(pressedKey.Key != ConsoleKey.Y && pressedKey.Key != ConsoleKey.N) - { - DicConsole - .Write("Drive supports SCSI READ LONG but I cannot find the correct size. Do you want me to try? (This can take hours) (Y/N): "); - pressedKey = System.Console.ReadKey(); - DicConsole.WriteLine(); - } - - if(pressedKey.Key == ConsoleKey.Y) - { - for(ushort i = (ushort)report.SCSI.ReadCapabilities.BlockSize;; i++) - { - DicConsole.Write("\rTrying to READ LONG with a size of {0} bytes...", i); - sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, i, TIMEOUT, - out _); - if(!sense) - { - if(debug) - { - FileStream bingo = - new FileStream($"{dev.Model}_readlong.bin", FileMode.Create); - bingo.Write(buffer, 0, buffer.Length); - bingo.Close(); - } - - report.SCSI.ReadCapabilities.LongBlockSize = i; - break; - } - - if(i == ushort.MaxValue) break; - } - - DicConsole.WriteLine(); - } - } - - if(debug && report.SCSI.ReadCapabilities.SupportsReadLong == true && - report.SCSI.ReadCapabilities.LongBlockSize != - report.SCSI.ReadCapabilities.BlockSize) - { - sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, - (ushort)report.SCSI.ReadCapabilities.LongBlockSize, TIMEOUT, out _); - if(!sense) - DataFile.WriteTo("SCSI Report", "readlong10", - "_debug_" + productIdentification + ".bin", "read results", buffer); - } - } - - break; } + + if(mediaTest.SupportsReadLong == true && mediaTest.LongBlockSize == mediaTest.BlockSize) + if(mediaTest.BlockSize == 512) + foreach(int i in new[] + { + // Long sector sizes for floppies + 514, + // Long sector sizes for SuperDisk + 536, 558, + // Long sector sizes for 512-byte magneto-opticals + 600, 610, 630 + }) + { + ushort testSize = (ushort)i; + sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, testSize, dev.Timeout, + out _); + if(sense || dev.Error) continue; + + mediaTest.SupportsReadLong = true; + mediaTest.LongBlockSize = testSize; + break; + } + else if(mediaTest.BlockSize == 1024) + foreach(int i in new[] + { + // Long sector sizes for floppies + 1026, + // Long sector sizes for 1024-byte magneto-opticals + 1200 + }) + { + ushort testSize = (ushort)i; + sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, (ushort)i, dev.Timeout, + out _); + if(sense || dev.Error) continue; + + mediaTest.SupportsReadLong = true; + mediaTest.LongBlockSize = testSize; + break; + } + else if(mediaTest.BlockSize == 2048) + { + sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, 2380, dev.Timeout, out _); + if(!sense && !dev.Error) + { + mediaTest.SupportsReadLong = true; + mediaTest.LongBlockSize = 2380; + } + } + else if(mediaTest.BlockSize == 4096) + { + sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, 4760, dev.Timeout, out _); + if(!sense && !dev.Error) + { + mediaTest.SupportsReadLong = true; + mediaTest.LongBlockSize = 4760; + } + } + else if(mediaTest.BlockSize == 8192) + { + sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, 9424, dev.Timeout, out _); + if(!sense && !dev.Error) + { + mediaTest.SupportsReadLong = true; + mediaTest.LongBlockSize = 9424; + } + } + + DicConsole.WriteLine("Trying SCSI READ MEDIA SERIAL NUMBER..."); + mediaTest.CanReadMediaSerial = !dev.ReadMediaSerialNumber(out buffer, out senseBuffer, dev.Timeout, out _); + + return mediaTest; + } + + public TestedMedia ReportScsi() + { + TestedMedia capabilities = new TestedMedia {MediaIsRecognized = true}; + + DicConsole.WriteLine("Querying SCSI READ CAPACITY..."); + bool sense = dev.ReadCapacity(out byte[] buffer, out byte[] senseBuffer, dev.Timeout, out _); + if(!sense && !dev.Error) + { + capabilities.SupportsReadCapacity = true; + capabilities.Blocks = + (ulong)((buffer[0] << 24) + (buffer[1] << 16) + (buffer[2] << 8) + buffer[3]) + 1; + capabilities.BlockSize = + (uint)((buffer[4] << 24) + (buffer[5] << 16) + (buffer[6] << 8) + buffer[7]); + } + + DicConsole.WriteLine("Querying SCSI READ CAPACITY (16)..."); + sense = dev.ReadCapacity16(out buffer, out buffer, dev.Timeout, out _); + if(!sense && !dev.Error) + { + capabilities.SupportsReadCapacity16 = true; + byte[] temp = new byte[8]; + Array.Copy(buffer, 0, temp, 0, 8); + Array.Reverse(temp); + capabilities.Blocks = BitConverter.ToUInt64(temp, 0) + 1; + capabilities.BlockSize = (uint)((buffer[8] << 24) + (buffer[9] << 16) + (buffer[10] << 8) + buffer[11]); + } + + Modes.DecodedMode? decMode = null; + + DicConsole.WriteLine("Querying SCSI MODE SENSE (10)..."); + sense = dev.ModeSense10(out buffer, out senseBuffer, false, true, ScsiModeSensePageControl.Current, 0x3F, + 0x00, dev.Timeout, out _); + if(!sense && !dev.Error) + { + decMode = Modes.DecodeMode10(buffer, dev.ScsiType); + if(debug) capabilities.ModeSense10Data = buffer; + } + + DicConsole.WriteLine("Querying SCSI MODE SENSE..."); + sense = dev.ModeSense(out buffer, out senseBuffer, dev.Timeout, out _); + if(!sense && !dev.Error) + { + if(!decMode.HasValue) decMode = Modes.DecodeMode6(buffer, dev.ScsiType); + if(debug) capabilities.ModeSense6Data = buffer; + } + + if(decMode.HasValue) + { + capabilities.MediumType = (byte)decMode.Value.Header.MediumType; + if(decMode.Value.Header.BlockDescriptors != null && decMode.Value.Header.BlockDescriptors.Length > 0) + capabilities.Density = (byte)decMode.Value.Header.BlockDescriptors[0].Density; + } + + DicConsole.WriteLine("Trying SCSI READ (6)..."); + capabilities.SupportsRead6 = !dev.Read6(out buffer, out senseBuffer, 0, capabilities.BlockSize ?? 512, + dev.Timeout, out _); + DicConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !capabilities.SupportsRead6); + if(debug) DataFile.WriteTo("SCSI Report", "read6", "_debug_" + dev.Model + ".bin", "read results", buffer); + + DicConsole.WriteLine("Trying SCSI READ (10)..."); + capabilities.SupportsRead10 = !dev.Read10(out buffer, out senseBuffer, 0, false, true, false, false, 0, + capabilities.BlockSize ?? 512, 0, 1, dev.Timeout, out _); + DicConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !capabilities.SupportsRead10); + if(debug) DataFile.WriteTo("SCSI Report", "read10", "_debug_" + dev.Model + ".bin", "read results", buffer); + + DicConsole.WriteLine("Trying SCSI READ (12)..."); + capabilities.SupportsRead12 = !dev.Read12(out buffer, out senseBuffer, 0, false, true, false, false, 0, + capabilities.BlockSize ?? 512, 0, 1, false, dev.Timeout, out _); + DicConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !capabilities.SupportsRead12); + if(debug) DataFile.WriteTo("SCSI Report", "read12", "_debug_" + dev.Model + ".bin", "read results", buffer); + + DicConsole.WriteLine("Trying SCSI READ (16)..."); + capabilities.SupportsRead16 = !dev.Read16(out buffer, out senseBuffer, 0, false, true, false, 0, + capabilities.BlockSize ?? 512, 0, 1, false, dev.Timeout, out _); + DicConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !capabilities.SupportsRead16); + if(debug) DataFile.WriteTo("SCSI Report", "read16", "_debug_" + dev.Model + ".bin", "read results", buffer); + + capabilities.LongBlockSize = capabilities.BlockSize; + DicConsole.WriteLine("Trying SCSI READ LONG (10)..."); + sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, 0xFFFF, dev.Timeout, out _); + if(sense && !dev.Error) + { + FixedSense? decSense = Sense.DecodeFixed(senseBuffer); + if(decSense.HasValue) + if(decSense.Value.SenseKey == SenseKeys.IllegalRequest && decSense.Value.ASC == 0x24 && + decSense.Value.ASCQ == 0x00) + { + capabilities.SupportsReadLong = true; + if(decSense.Value.InformationValid && decSense.Value.ILI) + capabilities.LongBlockSize = 0xFFFF - (decSense.Value.Information & 0xFFFF); + } + } + + if(capabilities.SupportsReadLong != true || capabilities.LongBlockSize != capabilities.BlockSize) + return capabilities; + + if(capabilities.BlockSize == 512) + foreach(int i in new[] + { + // Long sector sizes for floppies + 514, + // Long sector sizes for SuperDisk + 536, 558, + // Long sector sizes for 512-byte magneto-opticals + 600, 610, 630 + }) + { + ushort testSize = (ushort)i; + sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, (ushort)i, dev.Timeout, out _); + if(sense || dev.Error) continue; + + capabilities.SupportsReadLong = true; + capabilities.LongBlockSize = testSize; + break; + } + else if(capabilities.BlockSize == 1024) + foreach(int i in new[] + { + // Long sector sizes for floppies + 1026, + // Long sector sizes for 1024-byte magneto-opticals + 1200 + }) + { + ushort testSize = (ushort)i; + sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, (ushort)i, dev.Timeout, out _); + if(sense || dev.Error) continue; + + capabilities.SupportsReadLong = true; + capabilities.LongBlockSize = testSize; + break; + } + else if(capabilities.BlockSize == 2048) + { + sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, 2380, dev.Timeout, out _); + if(sense || dev.Error) return capabilities; + + capabilities.SupportsReadLong = true; + capabilities.LongBlockSize = 2380; + } + else if(capabilities.BlockSize == 4096) + { + sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, 4760, dev.Timeout, out _); + if(sense || dev.Error) return capabilities; + + capabilities.SupportsReadLong = true; + capabilities.LongBlockSize = 4760; + } + else if(capabilities.BlockSize == 8192) + { + sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, 9424, dev.Timeout, out _); + if(sense || dev.Error) return capabilities; + + capabilities.SupportsReadLong = true; + capabilities.LongBlockSize = 9424; + } + + return capabilities; } } } \ No newline at end of file diff --git a/DiscImageChef.Core/Devices/Report/SCSI/MMC.cs b/DiscImageChef.Core/Devices/Report/SCSI/MMC.cs index c94a6e30e..e21800c65 100644 --- a/DiscImageChef.Core/Devices/Report/SCSI/MMC.cs +++ b/DiscImageChef.Core/Devices/Report/SCSI/MMC.cs @@ -46,7 +46,7 @@ namespace DiscImageChef.Core.Devices.Report.SCSI /// /// Implements creating a report for a SCSI MultiMedia device /// - static class Mmc + public static class Mmc { /// /// Fills a SCSI device report with parameters and media tests specific to a MultiMedia device @@ -55,8 +55,8 @@ namespace DiscImageChef.Core.Devices.Report.SCSI /// Device report /// If debug is enabled /// Decoded MODE PAGE 2Ah - internal static void Report(Device dev, ref DeviceReportV2 report, bool debug, ref Modes.ModePage_2A? cdromMode, - string productIdentification) + public static void Report(Device dev, ref DeviceReportV2 report, bool debug, Modes.ModePage_2A? cdromMode, + string productIdentification) { if(report == null) return; diff --git a/DiscImageChef.Core/Devices/Report/SCSI/SSC.cs b/DiscImageChef.Core/Devices/Report/SCSI/SSC.cs index ba23b2434..ab6a3f18b 100644 --- a/DiscImageChef.Core/Devices/Report/SCSI/SSC.cs +++ b/DiscImageChef.Core/Devices/Report/SCSI/SSC.cs @@ -44,7 +44,7 @@ namespace DiscImageChef.Core.Devices.Report.SCSI /// /// Implements creating a report for a SCSI Streaming device /// - static class Ssc + public static class Ssc { /// /// Fills a SCSI device report with parameters and media tests specific to a Streaming device @@ -52,7 +52,7 @@ namespace DiscImageChef.Core.Devices.Report.SCSI /// Device /// Device report /// If debug is enabled - internal static void Report(Device dev, ref DeviceReportV2 report, bool debug) + public static void Report(Device dev, ref DeviceReportV2 report, bool debug) { if(report == null) return; diff --git a/DiscImageChef/Commands/DeviceReport.cs b/DiscImageChef/Commands/DeviceReport.cs index 8ba0c7adf..6f3e1a321 100644 --- a/DiscImageChef/Commands/DeviceReport.cs +++ b/DiscImageChef/Commands/DeviceReport.cs @@ -33,12 +33,16 @@ using System; using System.Collections.Generic; using System.IO; +using System.Threading; using DiscImageChef.CommonTypes.Metadata; using DiscImageChef.Console; -using DiscImageChef.Core.Devices.Report.SCSI; +using DiscImageChef.Core; using DiscImageChef.Decoders.ATA; +using DiscImageChef.Decoders.SCSI; using DiscImageChef.Devices; using Newtonsoft.Json; +using Mmc = DiscImageChef.Core.Devices.Report.SCSI.Mmc; +using Ssc = DiscImageChef.Core.Devices.Report.SCSI.Ssc; namespace DiscImageChef.Commands { @@ -224,8 +228,7 @@ namespace DiscImageChef.Commands case DeviceType.SecureDigital: report.SecureDigital = reporter.MmcSdReport(); break; - case DeviceType.NVMe: - throw new NotImplementedException("NVMe devices not yet supported."); + case DeviceType.NVMe: throw new NotImplementedException("NVMe devices not yet supported."); case DeviceType.ATAPI: DicConsole.WriteLine("Querying ATAPI IDENTIFY..."); @@ -234,13 +237,261 @@ namespace DiscImageChef.Commands if(!Identify.Decode(buffer).HasValue) return; Identify.IdentifyDevice? atapiIdNullable = Identify.Decode(buffer); - if(atapiIdNullable != null) report.ATAPI = new CommonTypes.Metadata.Ata {IdentifyDevice = atapiIdNullable}; + if(atapiIdNullable != null) report.ATAPI = new Ata {IdentifyDevice = atapiIdNullable}; if(options.Debug) report.ATAPI.Identify = buffer; goto case DeviceType.SCSI; case DeviceType.SCSI: - General.Report(dev, ref report, options.Debug, ref removable); + if(!dev.IsUsb && !dev.IsFireWire && dev.IsRemovable) + { + pressedKey = new ConsoleKeyInfo(); + while(pressedKey.Key != ConsoleKey.Y && pressedKey.Key != ConsoleKey.N) + { + DicConsole + .Write("Is the media removable from the reading/writing elements (flash memories ARE NOT removable)? (Y/N): "); + pressedKey = System.Console.ReadKey(); + DicConsole.WriteLine(); + } + + removable = pressedKey.Key == ConsoleKey.Y; + } + + if(removable) + { + switch(dev.ScsiType) + { + case PeripheralDeviceTypes.MultiMediaDevice: + dev.AllowMediumRemoval(out buffer, dev.Timeout, out _); + dev.EjectTray(out buffer, dev.Timeout, out _); + break; + case PeripheralDeviceTypes.SequentialAccess: + dev.SpcAllowMediumRemoval(out buffer, dev.Timeout, out _); + DicConsole.WriteLine("Asking drive to unload tape (can take a few minutes)..."); + dev.Unload(out buffer, dev.Timeout, out _); + break; + } + + DicConsole + .WriteLine("Please remove any media from the device and press any key when it is out."); + System.Console.ReadKey(true); + } + + report.SCSI = reporter.ReportScsiInquiry(); + if(report.SCSI == null) break; + + report.SCSI.EVPDPages = reporter.ReportEvpdPages(); + + Modes.ModePage_2A? cdromMode = null; + + reporter.ReportScsiModes(ref report, ref cdromMode); + + string productIdentification = null; + if(!string.IsNullOrWhiteSpace(StringHandlers.CToString(report.SCSI.Inquiry?.ProductIdentification))) + productIdentification = + StringHandlers.CToString(report.SCSI.Inquiry?.ProductIdentification).Trim(); + + switch(dev.ScsiType) + { + case PeripheralDeviceTypes.MultiMediaDevice: + Mmc.Report(dev, ref report, options.Debug, cdromMode, productIdentification); + break; + case PeripheralDeviceTypes.SequentialAccess: + Ssc.Report(dev, ref report, options.Debug); + break; + default: + { + 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); + + DicConsole.Write("Please write a description of the media type and press enter: "); + string mediumTypeName = System.Console.ReadLine(); + DicConsole.Write("Please write the media manufacturer and press enter: "); + string manufacturer = System.Console.ReadLine(); + DicConsole.Write("Please write the media model and press enter: "); + string model = System.Console.ReadLine(); + + bool mediaIsRecognized = true; + + bool sense = dev.ScsiTestUnitReady(out byte[] senseBuffer, dev.Timeout, out _); + if(sense) + { + FixedSense? decSense = Sense.DecodeFixed(senseBuffer); + if(decSense.HasValue) + if(decSense.Value.ASC == 0x3A) + { + int leftRetries = 20; + while(leftRetries > 0) + { + DicConsole.Write("\rWaiting for drive to become ready"); + Thread.Sleep(2000); + sense = dev.ScsiTestUnitReady(out senseBuffer, dev.Timeout, out _); + if(!sense) break; + + leftRetries--; + } + + mediaIsRecognized &= !sense; + } + else if(decSense.Value.ASC == 0x04 && decSense.Value.ASCQ == 0x01) + { + int leftRetries = 20; + while(leftRetries > 0) + { + DicConsole.Write("\rWaiting for drive to become ready"); + Thread.Sleep(2000); + sense = dev.ScsiTestUnitReady(out senseBuffer, dev.Timeout, out _); + if(!sense) break; + + leftRetries--; + } + + mediaIsRecognized &= !sense; + } + else mediaIsRecognized = false; + else mediaIsRecognized = false; + } + + TestedMedia mediaTest = new TestedMedia(); + + if(mediaIsRecognized) + { + mediaTest = reporter.ReportScsiMedia(); + + if(mediaTest.SupportsReadLong == true && + mediaTest.LongBlockSize == mediaTest.BlockSize) + { + pressedKey = new ConsoleKeyInfo(); + while(pressedKey.Key != ConsoleKey.Y && pressedKey.Key != ConsoleKey.N) + { + DicConsole + .Write("Drive supports SCSI READ LONG but I cannot find the correct size. Do you want me to try? (This can take hours) (Y/N): "); + pressedKey = System.Console.ReadKey(); + DicConsole.WriteLine(); + } + + if(pressedKey.Key == ConsoleKey.Y) + { + for(ushort i = (ushort)mediaTest.BlockSize;; i++) + { + DicConsole + .Write("\rTrying to READ LONG with a size of {0} bytes...", i); + sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, + i, dev.Timeout, out _); + if(!sense) + { + mediaTest.LongBlockSize = i; + break; + } + + if(i == ushort.MaxValue) break; + } + + DicConsole.WriteLine(); + } + } + + if(options.Debug && mediaTest.SupportsReadLong == true && + mediaTest.LongBlockSize != mediaTest.BlockSize) + { + sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, + (ushort)mediaTest.LongBlockSize, dev.Timeout, out _); + if(!sense) + DataFile.WriteTo("SCSI Report", "readlong10", + "_debug_" + mediaTest.MediumTypeName + ".bin", + "read results", buffer); + } + } + + mediaTest.MediumTypeName = mediumTypeName; + mediaTest.Manufacturer = manufacturer; + mediaTest.Model = model; + + mediaTests.Add(mediaTest); + } + + report.SCSI.RemovableMedias = mediaTests.ToArray(); + } + else + { + report.SCSI.ReadCapabilities = reporter.ReportScsi(); + + if(report.SCSI.ReadCapabilities.SupportsReadLong == true && + report.SCSI.ReadCapabilities.LongBlockSize == + report.SCSI.ReadCapabilities.BlockSize) + { + pressedKey = new ConsoleKeyInfo(); + while(pressedKey.Key != ConsoleKey.Y && pressedKey.Key != ConsoleKey.N) + { + DicConsole + .Write("Drive supports SCSI READ LONG but I cannot find the correct size. Do you want me to try? (This can take hours) (Y/N): "); + pressedKey = System.Console.ReadKey(); + DicConsole.WriteLine(); + } + + if(pressedKey.Key == ConsoleKey.Y) + { + for(ushort i = (ushort)report.SCSI.ReadCapabilities.BlockSize;; i++) + { + DicConsole.Write("\rTrying to READ LONG with a size of {0} bytes...", i); + bool sense = dev.ReadLong10(out buffer, out byte[] senseBuffer, false, + false, 0, i, dev.Timeout, out _); + if(!sense) + { + if(options.Debug) + { + FileStream bingo = + new FileStream($"{dev.Model}_readlong.bin", FileMode.Create); + bingo.Write(buffer, 0, buffer.Length); + bingo.Close(); + } + + report.SCSI.ReadCapabilities.LongBlockSize = i; + break; + } + + if(i == ushort.MaxValue) break; + } + + DicConsole.WriteLine(); + } + } + + if(options.Debug && report.SCSI.ReadCapabilities.SupportsReadLong == true && + report.SCSI.ReadCapabilities.LongBlockSize != + report.SCSI.ReadCapabilities.BlockSize) + { + bool sense = dev.ReadLong10(out buffer, out byte[] senseBuffer, false, false, 0, + (ushort)report.SCSI.ReadCapabilities.LongBlockSize, + dev.Timeout, out _); + if(!sense) + DataFile.WriteTo("SCSI Report", "readlong10", "_debug_" + dev.Model + ".bin", + "read results", buffer); + } + } + + break; + } + } + break; default: throw new NotSupportedException("Unknown device type."); }