From 92e3aa38b3c9a0c6f1acf45ca7f714a4b82fc73b Mon Sep 17 00:00:00 2001 From: Rebecca Wallander Date: Sat, 21 Feb 2026 19:31:09 +0100 Subject: [PATCH] Initial OmniDrive DVD read --- Aaru.Core/Devices/Dumping/Sbc/Dump.cs | 6 +- Aaru.Core/Devices/Dumping/Sbc/Error.cs | 2 +- .../Dumping/Sbc/{Cache.cs => RawDvd.cs} | 10 +- Aaru.Core/Devices/Dumping/Sbc/Trim.cs | 2 +- Aaru.Core/Devices/ReaderSCSI.cs | 23 +++- Aaru.Devices/Device/ScsiCommands/OmniDrive.cs | 109 ++++++++++++++++++ Aaru.Devices/Enums.cs | 7 ++ Aaru.Localization/Core.Designer.cs | 8 +- Aaru.Localization/Core.es.resx | 3 + Aaru.Localization/Core.resx | 3 + 10 files changed, 162 insertions(+), 11 deletions(-) rename Aaru.Core/Devices/Dumping/Sbc/{Cache.cs => RawDvd.cs} (96%) create mode 100644 Aaru.Devices/Device/ScsiCommands/OmniDrive.cs diff --git a/Aaru.Core/Devices/Dumping/Sbc/Dump.cs b/Aaru.Core/Devices/Dumping/Sbc/Dump.cs index 21a7c208c..e28902cdc 100644 --- a/Aaru.Core/Devices/Dumping/Sbc/Dump.cs +++ b/Aaru.Core/Devices/Dumping/Sbc/Dump.cs @@ -324,6 +324,7 @@ partial class Dump scsiReader.otp = decodedPfi is { Layers: 1, TrackPath: false }; if(scsiReader.HldtstReadRaw) blocksToRead = 1; + if(scsiReader.OmniDriveReadRaw) blocksToRead = 31; UpdateStatus?.Invoke(string.Format(Localization.Core.Reading_0_raw_bytes_1_cooked_bytes_per_sector, longBlockSize, @@ -804,9 +805,9 @@ partial class Dump { mediaTags.TryGetValue(MediaTagType.DVD_DiscKey_Decrypted, out byte[] discKey); - if(scsiReader.HldtstReadRaw || scsiReader.ReadBuffer3CReadRaw) + if(scsiReader.HldtstReadRaw || scsiReader.ReadBuffer3CReadRaw || scsiReader.OmniDriveReadRaw) { - ReadCacheData(blocks, + ReadRawDvdData(blocks, blocksToRead, blockSize, currentTry, @@ -905,6 +906,7 @@ partial class Dump // Unnecessary since keys are already in raw data !scsiReader.ReadBuffer3CReadRaw && + !scsiReader.OmniDriveReadRaw && !scsiReader.HldtstReadRaw && mediaTag is not null) RetryTitleKeys(dvdDecrypt, mediaTag, ref totalDuration); diff --git a/Aaru.Core/Devices/Dumping/Sbc/Error.cs b/Aaru.Core/Devices/Dumping/Sbc/Error.cs index 010bca909..a85059f37 100644 --- a/Aaru.Core/Devices/Dumping/Sbc/Error.cs +++ b/Aaru.Core/Devices/Dumping/Sbc/Error.cs @@ -306,7 +306,7 @@ partial class Dump _resume.BadBlocks.Remove(badSector); extents.Add(badSector); - if(scsiReader.ReadBuffer3CReadRaw || scsiReader.HldtstReadRaw) + if(scsiReader.ReadBuffer3CReadRaw || scsiReader.OmniDriveReadRaw || scsiReader.HldtstReadRaw) { var cmi = new byte[1]; diff --git a/Aaru.Core/Devices/Dumping/Sbc/Cache.cs b/Aaru.Core/Devices/Dumping/Sbc/RawDvd.cs similarity index 96% rename from Aaru.Core/Devices/Dumping/Sbc/Cache.cs rename to Aaru.Core/Devices/Dumping/Sbc/RawDvd.cs index 5881fa89e..b1a320325 100644 --- a/Aaru.Core/Devices/Dumping/Sbc/Cache.cs +++ b/Aaru.Core/Devices/Dumping/Sbc/RawDvd.cs @@ -2,7 +2,7 @@ // Aaru Data Preservation Suite // ---------------------------------------------------------------------------- // -// Filename : Cache.cs +// Filename : RawDvd.cs // Author(s) : Natalia Portillo // // --[ License ] -------------------------------------------------------------- @@ -44,8 +44,8 @@ namespace Aaru.Core.Devices.Dumping; partial class Dump { /// - /// Dumps data when dumping from a SCSI Block Commands compliant device, - /// and reads the data from the device cache + /// Dumps raw DVD sectors (2064-byte frames) when dumping from a SCSI Block Commands compliant device. + /// Supports HL-DT-ST, ReadBuffer 3C, and OmniDrive raw reading methods. /// /// Media blocks /// Maximum number of blocks to read in a single command @@ -62,7 +62,7 @@ partial class Dump /// Total time spent writing to image /// Set if we need to start a trim /// The DVD disc key - void ReadCacheData(in ulong blocks, in uint maxBlocksToRead, in uint blockSize, DumpHardware currentTry, + void ReadRawDvdData(in ulong blocks, in uint maxBlocksToRead, in uint blockSize, DumpHardware currentTry, ExtentsULong extents, ref double currentSpeed, ref double minSpeed, ref double maxSpeed, ref double totalDuration, Reader scsiReader, MhddLog mhddLog, IbgLog ibgLog, ref double imageWriteDuration, ref bool newTrim, byte[] discKey) @@ -216,4 +216,4 @@ partial class Dump EndProgress?.Invoke(); } -} \ No newline at end of file +} diff --git a/Aaru.Core/Devices/Dumping/Sbc/Trim.cs b/Aaru.Core/Devices/Dumping/Sbc/Trim.cs index fedbf22c1..74c0ac712 100644 --- a/Aaru.Core/Devices/Dumping/Sbc/Trim.cs +++ b/Aaru.Core/Devices/Dumping/Sbc/Trim.cs @@ -99,7 +99,7 @@ partial class Dump _resume.BadBlocks.Remove(badSector); extents.Add(badSector); - if(scsiReader.ReadBuffer3CReadRaw || scsiReader.HldtstReadRaw) + if(scsiReader.ReadBuffer3CReadRaw || scsiReader.OmniDriveReadRaw || scsiReader.HldtstReadRaw) { var cmi = new byte[1]; diff --git a/Aaru.Core/Devices/ReaderSCSI.cs b/Aaru.Core/Devices/ReaderSCSI.cs index a6f0b8872..a43827fc9 100644 --- a/Aaru.Core/Devices/ReaderSCSI.cs +++ b/Aaru.Core/Devices/ReaderSCSI.cs @@ -55,6 +55,7 @@ sealed partial class Reader // TODO: Raw reading public bool HldtstReadRaw; public uint layerbreak; + public bool OmniDriveReadRaw; public bool ReadBuffer3CReadRaw; public bool otp; @@ -587,7 +588,14 @@ sealed partial class Reader ReadBuffer3CReadRaw = !_dev.ReadBuffer3CRawDvd(out _, out senseBuf, 0, 1, _timeout, out _, layerbreak, otp); - if(HldtstReadRaw || _plextorReadRaw || ReadBuffer3CReadRaw) + // Try OmniDrive on drives with OmniDrive firmware + if(_dev.IsOmniDriveFirmware()) + { + OmniDriveReadRaw = + !_dev.OmniDriveReadRawDvd(out _, out senseBuf, 0, 1, _timeout, out _); + } + + if(HldtstReadRaw || _plextorReadRaw || ReadBuffer3CReadRaw || OmniDriveReadRaw) { CanReadRaw = true; LongBlockSize = 2064; @@ -622,6 +630,8 @@ sealed partial class Reader AaruLogging.WriteLine($"[slateblue1]{Localization.Core.Using_HL_DT_ST_raw_DVD_reading}[/]"); else if(_plextorReadRaw) AaruLogging.WriteLine($"[slateblue1]{Localization.Core.Using_Plextor_raw_DVD_reading}[/]"); + else if(OmniDriveReadRaw) + AaruLogging.WriteLine($"[slateblue1]{Localization.Core.Using_OmniDrive_raw_DVD_reading}[/]"); else if(ReadBuffer3CReadRaw) AaruLogging.WriteLine($"[slateblue1]{Localization.Core.Using_ReadBuffer_3C_raw_DVD_reading}[/]"); } @@ -687,6 +697,8 @@ sealed partial class Reader { if(HldtstReadRaw || ReadBuffer3CReadRaw) BlocksToRead = 1; + else if(OmniDriveReadRaw) + BlocksToRead = (uint)Math.Min(31, startWithBlocks); else if(_read6) { _dev.Read6(out _, out _, 0, LogicalBlockSize, (byte)BlocksToRead, _timeout, out _); @@ -833,6 +845,15 @@ sealed partial class Reader _timeout, out duration); } + else if(OmniDriveReadRaw) + { + sense = _dev.OmniDriveReadRawDvd(out buffer, + out senseBuf, + (uint)block, + count, + _timeout, + out duration); + } else if(ReadBuffer3CReadRaw) { sense = _dev.ReadBuffer3CRawDvd(out buffer, diff --git a/Aaru.Devices/Device/ScsiCommands/OmniDrive.cs b/Aaru.Devices/Device/ScsiCommands/OmniDrive.cs new file mode 100644 index 000000000..2d75a548b --- /dev/null +++ b/Aaru.Devices/Device/ScsiCommands/OmniDrive.cs @@ -0,0 +1,109 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : OmniDrive.cs +// Author(s) : Rebecca Wallander +// +// Component : OmniDrive firmware vendor commands. +// +// --[ Description ] ---------------------------------------------------------- +// +// Contains vendor commands for OmniDrive firmware. OmniDrive is custom +// firmware that adds SCSI command 0xC0 to read raw DVD sectors (2064 bytes) +// directly by LBA. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2026 Rebecca Wallander +// ****************************************************************************/ + +using System; +using Aaru.CommonTypes.Structs.Devices.SCSI; +using Aaru.Logging; + +namespace Aaru.Devices; + +public partial class Device +{ + /// + /// Checks if the drive has OmniDrive firmware by inspecting INQUIRY Reserved5 (bytes 74+) for "OmniDrive", + /// matching redumper's is_omnidrive_firmware behaviour. + /// + /// true if Reserved5 starts with "OmniDrive" and has at least 11 bytes (8 + 3 for version). + public bool IsOmniDriveFirmware() + { + bool sense = ScsiInquiry(out byte[] buffer, out _, Timeout, out _); + + if(sense || buffer == null) return false; + + Inquiry? inquiry = Inquiry.Decode(buffer); + + if(!inquiry.HasValue || inquiry.Value.Reserved5 == null || inquiry.Value.Reserved5.Length < 11) + return false; + + byte[] reserved5 = inquiry.Value.Reserved5; + byte[] omnidrive = [0x4F, 0x6D, 0x6E, 0x69, 0x44, 0x72, 0x69, 0x76, 0x65]; // "OmniDrive" + + if(reserved5.Length < omnidrive.Length) return false; + + for(int i = 0; i < omnidrive.Length; i++) + if(reserved5[i] != omnidrive[i]) + return false; + + return true; + } + + /// Reads raw DVD sectors (2064 bytes) directly by LBA on OmniDrive firmware. + /// true if the command failed and contains the sense buffer. + /// Buffer where the raw DataFrame response will be stored + /// Sense buffer. + /// Start block address (LBA). + /// Number of 2064-byte sectors to read. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + public bool OmniDriveReadRawDvd(out byte[] buffer, out ReadOnlySpan senseBuffer, uint lba, uint transferLength, + uint timeout, out double duration) + { + senseBuffer = SenseBuffer; + Span cdb = CdbBuffer[..12]; + cdb.Clear(); + + buffer = new byte[2064 * transferLength]; + + cdb[0] = (byte)ScsiCommands.ReadOmniDrive; + cdb[1] = 0x11; // disc_type=1 (DVD), raw_addressing=0 (LBA), fua=0, descramble=1 + cdb[2] = (byte)((lba >> 24) & 0xFF); + cdb[3] = (byte)((lba >> 16) & 0xFF); + cdb[4] = (byte)((lba >> 8) & 0xFF); + cdb[5] = (byte)(lba & 0xFF); + cdb[6] = (byte)((transferLength >> 24) & 0xFF); + cdb[7] = (byte)((transferLength >> 16) & 0xFF); + cdb[8] = (byte)((transferLength >> 8) & 0xFF); + cdb[9] = (byte)(transferLength & 0xFF); + cdb[10] = 0; // subchannels=NONE, c2=0 + cdb[11] = 0; // control + + LastError = SendScsiCommand(cdb, ref buffer, timeout, ScsiDirection.In, out duration, out bool sense); + + Error = LastError != 0; + + AaruLogging.Debug(SCSI_MODULE_NAME, "OmniDrive READ RAW DVD took {0} ms", duration); + + return sense; + } +} diff --git a/Aaru.Devices/Enums.cs b/Aaru.Devices/Enums.cs index 014d220b6..25db2933d 100644 --- a/Aaru.Devices/Enums.cs +++ b/Aaru.Devices/Enums.cs @@ -1885,6 +1885,13 @@ public enum ScsiCommands : byte #endregion HL-DT-ST vendor commands +#region OmniDrive vendor commands + + /// Reads raw DVD sectors directly by LBA/PSN (OmniDrive firmware) + ReadOmniDrive = 0xC0, + +#endregion OmniDrive vendor commands + #region NEC vendor commands /// Reads CD-DA data diff --git a/Aaru.Localization/Core.Designer.cs b/Aaru.Localization/Core.Designer.cs index 3f4827d39..c4e5521b4 100644 --- a/Aaru.Localization/Core.Designer.cs +++ b/Aaru.Localization/Core.Designer.cs @@ -1,4 +1,4 @@ -//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ // // This code was generated by a tool. // @@ -6839,6 +6839,12 @@ namespace Aaru.Localization { } } + public static string Using_OmniDrive_raw_DVD_reading { + get { + return ResourceManager.GetString("Using_OmniDrive_raw_DVD_reading", resourceCulture); + } + } + public static string Using_ReadBuffer_3C_raw_DVD_reading { get { return ResourceManager.GetString("Using_ReadBuffer_3C_raw_DVD_reading", resourceCulture); diff --git a/Aaru.Localization/Core.es.resx b/Aaru.Localization/Core.es.resx index 3f9dc3f66..cc56a0a9d 100644 --- a/Aaru.Localization/Core.es.resx +++ b/Aaru.Localization/Core.es.resx @@ -3271,6 +3271,9 @@ No tiene sentido hacerlo y supondría demasiado esfuerzo para la cinta. [slateblue1]Usando comando [fuchsia]MMC READ CD[/].[/] + + [slateblue1]Usando lectura de [fuchsia]DVD sin procesar de OmniDrive[/].[/] + [slateblue1]Usando lectura de [fuchsia]DVD sin procesar de Plextor[/].[/] diff --git a/Aaru.Localization/Core.resx b/Aaru.Localization/Core.resx index 81356051d..fe0c108f1 100644 --- a/Aaru.Localization/Core.resx +++ b/Aaru.Localization/Core.resx @@ -3490,6 +3490,9 @@ It has no sense to do it, and it will put too much strain on the tape. [slateblue1]Using [fuchsia]Lite-On raw DVD[/] reading[/] + + [slateblue1]Using [fuchsia]OmniDrive[/] raw DVD reading[/] + [slateblue1]Using [fuchsia]ReadBuffer 3C raw DVD[/] reading[/]