diff --git a/Aaru.Server.New/Components/Pages/Report/View.razor b/Aaru.Server.New/Components/Pages/Report/View.razor index 5a2c92e6..0e6983af 100644 --- a/Aaru.Server.New/Components/Pages/Report/View.razor +++ b/Aaru.Server.New/Components/Pages/Report/View.razor @@ -35,7 +35,7 @@

- @lblDeviceType
+ @DeviceType

@if(UsbItem is not null) @@ -835,4 +835,45 @@ } -
\ No newline at end of file + + +@if(MediaInformation?.Count > 0) +{ +
+

+ Tested media information
+

+ + + @foreach(KeyValuePair Table, List List)> mediaInfo in MediaInformation) + { + + + + @mediaInfo.Key + + + + + + @foreach(KeyValuePair kvp in mediaInfo.Value.Table) + { + + @kvp.Key + @kvp.Value + + } + +
+ + @foreach(string cap in mediaInfo.Value.List) + { + @cap + } + +
+
+ } +
+
+} \ No newline at end of file diff --git a/Aaru.Server.New/Components/Pages/Report/View.razor.cs b/Aaru.Server.New/Components/Pages/Report/View.razor.cs index 00b70d26..a8f09d22 100644 --- a/Aaru.Server.New/Components/Pages/Report/View.razor.cs +++ b/Aaru.Server.New/Components/Pages/Report/View.razor.cs @@ -10,6 +10,7 @@ using Microsoft.EntityFrameworkCore; using Ata = Aaru.CommonTypes.Metadata.Ata; using DbContext = Aaru.Server.Database.DbContext; using Inquiry = Aaru.CommonTypes.Structs.Devices.SCSI.Inquiry; +using TestedMedia = Aaru.CommonTypes.Metadata.TestedMedia; using Tuple = Aaru.Decoders.PCMCIA.Tuple; namespace Aaru.Server.New.Components.Pages.Report; @@ -18,7 +19,6 @@ public partial class View { bool _initialized; bool _notFound; - bool accordionItem1Visible; string _pageTitle { get; set; } = "Aaru Device Report"; [CascadingParameter] HttpContext HttpContext { get; set; } = default!; @@ -28,7 +28,7 @@ public partial class View public Item? FireWireItem { get; set; } public Dictionary? PcmciaTuples { get; set; } public PcmciaItem? PcmciaItem { get; set; } - public string? lblDeviceType { get; set; } + public string? DeviceType { get; set; } public string? AtaItem { get; set; } public string? MaximumAtaRevision { get; set; } public List? SupportedAtaVersions { get; set; } @@ -58,16 +58,18 @@ public partial class View public List? InquiryCapabilities { get; set; } public List? ModeSenseCapabilities { get; set; } public Dictionary>? ModeSensePages { get; set; } - public List? BlockDescriptors { get; set; } - public List? ScsiSscMedias { get; set; } - public List? ScsiSscDensities { get; set; } - public string? ScsiSscMinBlock { get; set; } - public string? ScsiSscMaxBlock { get; set; } - public string? ScsiSscGranularity { get; set; } - public bool ScsiSscVisible { get; set; } - public List? MmcFeaturesList { get; set; } - public List? MmcModeList { get; set; } - public Dictionary>? EvpdPages { get; set; } + public List? BlockDescriptors { get; set; } + public List? ScsiSscMedias { get; set; } + public List? ScsiSscDensities { get; set; } + public string? ScsiSscMinBlock { get; set; } + public string? ScsiSscMaxBlock { get; set; } + public string? ScsiSscGranularity { get; set; } + public bool ScsiSscVisible { get; set; } + public List? MmcFeaturesList { get; set; } + public List? MmcModeList { get; set; } + public Dictionary>? EvpdPages { get; set; } + + public Dictionary Table, List List)>? MediaInformation { get; set; } /// protected override async Task OnInitializedAsync() @@ -112,6 +114,14 @@ public partial class View .ThenInclude(static ssc => ssc.SupportedMediaTypes) .Include(static deviceReportV2 => deviceReportV2.SCSI) .ThenInclude(static scsi => scsi.ReadCapabilities) + .Include(static deviceReportV2 => deviceReportV2.SCSI) + .ThenInclude(static scsi => scsi.SequentialDevice) + .ThenInclude(static ssc => ssc.TestedMedia) + .Include(static deviceReportV2 => deviceReportV2.SCSI) + .ThenInclude(static scsi => scsi.RemovableMedias) + .Include(static deviceReportV2 => deviceReportV2.SCSI) + .ThenInclude(static scsi => scsi.MultiMediaDevice) + .ThenInclude(static mmc => mmc.TestedMedia) .FirstOrDefaultAsync(d => d.Id == Id); if(report is null) @@ -269,9 +279,10 @@ public partial class View } } - var removable = true; - List? testedMedia; - var atapi = false; + var removable = true; + List? testedMedia = null; + var atapi = false; + var sscMedia = false; if(report.ATA != null || report.ATAPI != null) { @@ -291,12 +302,12 @@ public partial class View bool cfa = report.CompactFlash; - lblDeviceType = atapi switch - { - true when !cfa => "ATAPI device", - false when cfa => "CompactFlash device", - _ => "ATA device" - }; + DeviceType = atapi switch + { + true when !cfa => "ATAPI device", + false when cfa => "CompactFlash device", + _ => "ATA device" + }; Core.Ata.Report(ataReport!, cfa, @@ -346,7 +357,7 @@ public partial class View if(report.MultiMediaCard != null) { - lblDeviceType = "MultiMediaCard"; + DeviceType = "MultiMediaCard"; if(report.MultiMediaCard.CID != null) Cid = Decoders.MMC.Decoders.PrettifyCID(report.MultiMediaCard.CID).Replace("\n", "
"); @@ -366,7 +377,7 @@ public partial class View if(report.SecureDigital != null) { - lblDeviceType = "SecureDigital"; + DeviceType = "SecureDigital"; if(report.SecureDigital.CID != null) Cid = Decoders.SecureDigital.Decoders.PrettifyCID(report.SecureDigital.CID).Replace("\n", "
"); @@ -381,6 +392,7 @@ public partial class View Ocr = Decoders.SecureDigital.Decoders.PrettifyCSD(report.SecureDigital.OCR).Replace("\n", "
"); } + if(report.SCSI != null) { var vendorId = ""; @@ -388,16 +400,23 @@ public partial class View if(report.SCSI.Inquiry != null) { Inquiry inq = report.SCSI.Inquiry.Value; - vendorId = StringHandlers.CToString(report.SCSI.Inquiry?.VendorIdentification); - DeviceInquiry = new Dictionary(); + vendorId = StringHandlers.CToString(report.SCSI.Inquiry?.VendorIdentification); - DeviceInquiry.Add("Vendor:", - VendorString.Prettify(vendorId) != vendorId - ? $"{vendorId} ({VendorString.Prettify(vendorId)})" - : vendorId); - - DeviceInquiry.Add("Product:", StringHandlers.CToString(inq.ProductIdentification)); - DeviceInquiry.Add("Revision:", StringHandlers.CToString(inq.ProductRevisionLevel)); + DeviceInquiry = new Dictionary + { + { + "Vendor:", + VendorString.Prettify(vendorId) != vendorId + ? $"{vendorId} ({VendorString.Prettify(vendorId)})" + : vendorId + }, + { + "Product:", StringHandlers.CToString(inq.ProductIdentification) + }, + { + "Revision:", StringHandlers.CToString(inq.ProductRevisionLevel) + } + }; } List inquiryCapabilities = ScsiInquiry.Report(report.SCSI.Inquiry); @@ -439,7 +458,7 @@ public partial class View if(modeSenseCapabilities is not null) { - ModeSenseCapabilities ??= new List(); + ModeSenseCapabilities ??= []; ModeSenseCapabilities.AddRange(modeSenseCapabilities); } @@ -455,7 +474,7 @@ public partial class View if(report.SCSI.MultiMediaDevice is not null) { - // testedMedia = report.SCSI.MultiMediaDevice.TestedMedia; + testedMedia = report.SCSI.MultiMediaDevice.TestedMedia; if(report.SCSI.MultiMediaDevice.ModeSense2A != null) { @@ -487,20 +506,20 @@ public partial class View if(report.SCSI.SequentialDevice.SupportedMediaTypes != null) ScsiSscMedias = report.SCSI.SequentialDevice.SupportedMediaTypes; -/* if(report.SCSI.SequentialDevice.TestedMedia != null) - { - List mediaOneValue = new(); - SscTestedMedia.Report(report.SCSI.SequentialDevice.TestedMedia, ref mediaOneValue); + if(report.SCSI.SequentialDevice.TestedMedia != null) + { + sscMedia = true; - if(mediaOneValue.Count > 0) - { - sscMedia = true; - ViewBag.repTestedMedia = mediaOneValue; - } - }*/ + SscTestedMedia.Report(report.SCSI.SequentialDevice.TestedMedia, + out Dictionary Table, List List)> + mediaInformation); + + if(mediaInformation.Count > 0) MediaInformation = mediaInformation; + } } else if(report.SCSI.ReadCapabilities != null) { + removable = false; List readCapabilitiesList = []; var readCapabilitiesDictionary = new Dictionary(); @@ -530,8 +549,10 @@ public partial class View } if(report.SCSI.ReadCapabilities.MediumType.HasValue) + { readCapabilitiesDictionary.Add("Medium type code", $"{report.SCSI.ReadCapabilities.MediumType:X2}h"); + } if(report.SCSI.ReadCapabilities.Density.HasValue) readCapabilitiesDictionary.Add("Density code", $"{report.SCSI.ReadCapabilities.Density:X2}h"); @@ -539,8 +560,10 @@ public partial class View if((report.SCSI.ReadCapabilities.SupportsReadLong == true || report.SCSI.ReadCapabilities.SupportsReadLong16 == true) && report.SCSI.ReadCapabilities.LongBlockSize.HasValue) + { readCapabilitiesDictionary.Add("Long block size", $"{report.SCSI.ReadCapabilities.LongBlockSize} bytes"); + } if(report.SCSI.ReadCapabilities.SupportsReadCapacity == true) readCapabilitiesList.Add("Device supports READ CAPACITY (10) command."); @@ -569,9 +592,17 @@ public partial class View if(readCapabilitiesList.Count > 0) ReadCapabilitiesList = readCapabilitiesList; if(readCapabilitiesDictionary.Count > 0) ReadCapabilitiesDictionary = readCapabilitiesDictionary; } - /* else - testedMedia = report.SCSI.RemovableMedias; - */ + else + testedMedia = report.SCSI.RemovableMedias; + } + + if(removable && !sscMedia && testedMedia != null) + { + Core.TestedMedia.Report(testedMedia, + out Dictionary Table, List List)> + mediaInformation); + + if(mediaInformation.Count > 0) MediaInformation = mediaInformation; } _initialized = true; diff --git a/Aaru.Server.New/Core/Ata.cs b/Aaru.Server.New/Core/Ata.cs index e8a18d84..4e361e4f 100644 --- a/Aaru.Server.New/Core/Ata.cs +++ b/Aaru.Server.New/Core/Ata.cs @@ -30,7 +30,6 @@ // Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -using Aaru.CommonTypes.Metadata; using Aaru.CommonTypes.Structs.Devices.ATA; using Aaru.CommonTypes.Structs.Devices.SCSI; @@ -68,7 +67,8 @@ public static class Ata /// Dictionary of read capabilities for non-removable media /// List of read capabilities for non-removable media public static void Report(CommonTypes.Metadata.Ata ataReport, bool cfa, bool atapi, ref bool removable, - out List? testedMedia, out Dictionary? deviceIdentification, + out List? testedMedia, + out Dictionary? deviceIdentification, out List supportedAtaVersions, out string? maximumAtaRevision, out string? transport, out List? transportVersions, out List generalConfiguration, out List? specificConfiguration, @@ -1672,12 +1672,14 @@ public static class Ata !ataIdentify.CommandSet3.HasFlag(Identify.CommandSetBit3.MustBeClear) && ataIdentify.CommandSet3.HasFlag(Identify.CommandSetBit3.Streaming)) { - streaming = []; - streaming.Add($"Minimum request size is {ataIdentify.StreamMinReqSize}"); - streaming.Add($"Streaming transfer time in PIO is {ataIdentify.StreamTransferTimePIO}"); - streaming.Add($"Streaming transfer time in DMA is {ataIdentify.StreamTransferTimeDMA}"); - streaming.Add($"Streaming access latency is {ataIdentify.StreamAccessLatency}"); - streaming.Add($"Streaming performance granularity is {ataIdentify.StreamPerformanceGranularity}"); + streaming = + [ + $"Minimum request size is {ataIdentify.StreamMinReqSize}", + $"Streaming transfer time in PIO is {ataIdentify.StreamTransferTimePIO}", + $"Streaming transfer time in DMA is {ataIdentify.StreamTransferTimeDMA}", + $"Streaming access latency is {ataIdentify.StreamAccessLatency}", + $"Streaming performance granularity is {ataIdentify.StreamPerformanceGranularity}" + ]; } if(ataIdentify.SCTCommandTransport.HasFlag(Identify.SCTCommandTransportBit.Supported)) @@ -1702,8 +1704,7 @@ public static class Ata if((ataIdentify.NVCacheCaps & 0x0010) == 0x0010) { - nvCache = []; - nvCache.Add($"Version {(ataIdentify.NVCacheCaps & 0xF000) >> 12}"); + nvCache = [$"Version {(ataIdentify.NVCacheCaps & 0xF000) >> 12}"]; if((ataIdentify.NVCacheCaps & 0x0001) == 0x0001) { @@ -1741,12 +1742,16 @@ public static class Ata } if(ataReport.ReadCapabilities.PhysicalBlockSize != null) + { readCapabilitiesDictionary.Add("Physical sector size", $"{ataReport.ReadCapabilities.PhysicalBlockSize} bytes"); + } if(ataReport.ReadCapabilities.LongBlockSize != null) + { readCapabilitiesDictionary.Add("READ LONG sector size", $"{ataReport.ReadCapabilities.LongBlockSize} bytes"); + } if(ataReport.ReadCapabilities.BlockSize != null && ataReport.ReadCapabilities.PhysicalBlockSize != null && @@ -1847,12 +1852,16 @@ public static class Ata if(ata1 || cfa) { if(ataReport.ReadCapabilities.UnformattedBPT > 0) + { readCapabilitiesDictionary.Add("Bytes per unformatted track", $"{ataReport.ReadCapabilities.UnformattedBPT}"); + } if(ataReport.ReadCapabilities.UnformattedBPS > 0) + { readCapabilitiesDictionary.Add("Bytes per unformatted sector", $"{ataReport.ReadCapabilities.UnformattedBPS}"); + } } } diff --git a/Aaru.Server.New/Core/ScsiInquiry.cs b/Aaru.Server.New/Core/ScsiInquiry.cs index 0a16c4a3..1f8d29ff 100644 --- a/Aaru.Server.New/Core/ScsiInquiry.cs +++ b/Aaru.Server.New/Core/ScsiInquiry.cs @@ -44,7 +44,7 @@ static class ScsiInquiry /// List of values internal static List Report(Inquiry? inquiryNullable) { - List scsiOneValue = new(); + List scsiOneValue = []; if(!inquiryNullable.HasValue) return scsiOneValue; diff --git a/Aaru.Server.New/Core/SscTestedMedia.cs b/Aaru.Server.New/Core/SscTestedMedia.cs new file mode 100644 index 00000000..f1b6ce39 --- /dev/null +++ b/Aaru.Server.New/Core/SscTestedMedia.cs @@ -0,0 +1,79 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : SscTestedMedia.cs +// Author(s) : Natalia Portillo +// +// Component : Aaru Server. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SCSI Streaming media tests from reports. +// +// --[ 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-2024 Natalia Portillo +// ****************************************************************************/ + +using Aaru.CommonTypes.Metadata; + +namespace Aaru.Server.New.Core; + +public static class SscTestedMedia +{ + /// Takes the tested media from SCSI Streaming devices of a device report and prints it as a list of values + /// List to put values on + /// List of tested media + public static void Report(IEnumerable testedMedia, + out Dictionary Table, List List)> + mediaInformation) + { + mediaInformation = new Dictionary, List)>(); + + foreach(TestedSequentialMedia media in testedMedia) + { + Dictionary table = new(); + List list = []; + string header; + + if(!string.IsNullOrWhiteSpace(media.MediumTypeName)) + { + header = $"Information for medium named \"{media.MediumTypeName}\""; + + if(media.MediumType.HasValue) table.Add("Medium type code", $"{media.MediumType:X2}h"); + } + else if(media.MediumType.HasValue) + header = $"Information for medium type {media.MediumType:X2}h"; + else + header = "Information for unknown medium type"; + + if(!string.IsNullOrWhiteSpace(media.Manufacturer)) + table.Add("Medium manufacturer", $"{media.Manufacturer}"); + + if(!string.IsNullOrWhiteSpace(media.Model)) table.Add("Medium model", $"{media.Model}"); + + if(media.Density.HasValue) list.Add($"Medium has density code {media.Density:X2}h"); + + if(media.CanReadMediaSerial == true) list.Add("Drive can read medium serial number."); + + if(media.MediaIsRecognized) list.Add("Drive recognizes this medium."); + + mediaInformation.Add(header, (table, list)); + } + } +} \ No newline at end of file diff --git a/Aaru.Server.New/Core/TestedMedia.cs b/Aaru.Server.New/Core/TestedMedia.cs new file mode 100644 index 00000000..d3a2aef7 --- /dev/null +++ b/Aaru.Server.New/Core/TestedMedia.cs @@ -0,0 +1,390 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : TestedMedia.cs +// Author(s) : Natalia Portillo +// +// Component : Aaru Server. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes media tests from reports. +// +// --[ 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-2024 Natalia Portillo +// ****************************************************************************/ + +namespace Aaru.Server.New.Core; + +public static class TestedMedia +{ + /// Takes the tested media from a device report and prints it as a list of values + /// List to put values on + /// List of tested media + public static void Report(List testedMedias, + out Dictionary, List)> mediaInformation) + { + mediaInformation = new Dictionary, List)>(); + + foreach(CommonTypes.Metadata.TestedMedia testedMedia in testedMedias) + { + Dictionary table = new(); + List list = []; + string header; + + if(!string.IsNullOrWhiteSpace(testedMedia.MediumTypeName)) + { + header = $"Information for medium named \"{testedMedia.MediumTypeName}\""; + + if(testedMedia.MediumType != null) table.Add("Medium type code", $"{testedMedia.MediumType:X2}h"); + } + else if(testedMedia.MediumType != null) + header = $"Information for medium type {testedMedia.MediumType:X2}h"; + else + header = "Information for unknown medium type"; + + list.Add(testedMedia.MediaIsRecognized + ? "Drive recognizes this medium." + : "Drive does not recognize this medium."); + + if(!string.IsNullOrWhiteSpace(testedMedia.Manufacturer)) + table.Add("Medium manufacturer", $"{testedMedia.Manufacturer}"); + + if(!string.IsNullOrWhiteSpace(testedMedia.Model)) table.Add("Medium model", $"{testedMedia.Model}"); + + if(testedMedia.Density != null) table.Add("Density code", $"{testedMedia.Density:X2}h"); + + if(testedMedia.BlockSize != null) table.Add("Logical sector size", $"{testedMedia.BlockSize} bytes"); + + if(testedMedia.PhysicalBlockSize != null) + table.Add("Physical sector size", $"{testedMedia.PhysicalBlockSize} bytes"); + + if(testedMedia.LongBlockSize != null) + table.Add("READ LONG sector size", $"{testedMedia.LongBlockSize} bytes"); + + if(testedMedia is { Blocks: not null, BlockSize: not null }) + { + table.Add("Blocks", $"{testedMedia.Blocks}"); + table.Add("Block size", $"{testedMedia.BlockSize} bytes per block"); + + if(testedMedia.Blocks * testedMedia.BlockSize / 1024 / 1024 > 1000000) + { + table.Add("Medium size", + $"{testedMedia.Blocks * testedMedia.BlockSize} bytes, {testedMedia.Blocks * testedMedia.BlockSize / 1000 / 1000 / 1000 / 1000} Tb, {(double)(testedMedia.Blocks * testedMedia.BlockSize) / 1024 / 1024 / 1024 / 1024:F2} TiB"); + } + else if(testedMedia.Blocks * testedMedia.BlockSize / 1024 / 1024 > 1000) + { + table.Add("Medium size", + $"{testedMedia.Blocks * testedMedia.BlockSize} bytes, {testedMedia.Blocks * testedMedia.BlockSize / 1000 / 1000 / 1000} Gb, {(double)(testedMedia.Blocks * testedMedia.BlockSize) / 1024 / 1024 / 1024:F2} GiB"); + } + else + { + table.Add("Medium size", + $"{testedMedia.Blocks * testedMedia.BlockSize} bytes, {testedMedia.Blocks * testedMedia.BlockSize / 1000 / 1000} Mb, {(double)(testedMedia.Blocks * testedMedia.BlockSize) / 1024 / 1024:F2} MiB"); + } + } + + if(testedMedia is { CHS: not null, CurrentCHS: not null }) + { + int currentSectors = testedMedia.CurrentCHS.Cylinders * + testedMedia.CurrentCHS.Heads * + testedMedia.CurrentCHS.Sectors; + + table.Add("Cylinders", $"{testedMedia.CHS.Cylinders} max., {testedMedia.CurrentCHS.Cylinders} current"); + + table.Add("Heads", $"{testedMedia.CHS.Heads} max., {testedMedia.CurrentCHS.Heads} current"); + + table.Add("Sectors per track", + $"{testedMedia.CHS.Sectors} max., {testedMedia.CurrentCHS.Sectors} current"); + + table.Add("Sectors addressable in CHS mode", + $"{testedMedia.CHS.Cylinders * testedMedia.CHS.Heads * testedMedia.CHS.Sectors} max., {currentSectors} current"); + + table.Add("Medium size in CHS mode", + $"{(ulong)currentSectors * testedMedia.BlockSize} bytes, {(ulong)currentSectors * testedMedia.BlockSize / 1000 / 1000} Mb, {(double)((ulong)currentSectors * testedMedia.BlockSize) / 1024 / 1024:F2} MiB"); + } + else if(testedMedia.CHS != null) + { + int currentSectors = testedMedia.CHS.Cylinders * testedMedia.CHS.Heads * testedMedia.CHS.Sectors; + table.Add("Cylinders", $"{testedMedia.CHS.Cylinders}"); + table.Add("Heads", $"{testedMedia.CHS.Heads}"); + table.Add("Sectors per track", $"{testedMedia.CHS.Sectors}"); + table.Add("Sectors addressable in CHS mode", $"{currentSectors}"); + + table.Add("Medium size in CHS mode", + $"{(ulong)currentSectors * testedMedia.BlockSize} bytes, {(ulong)currentSectors * testedMedia.BlockSize / 1000 / 1000} Mb, {(double)((ulong)currentSectors * testedMedia.BlockSize) / 1024 / 1024:F2} MiB"); + } + + if(testedMedia.LBASectors != null) + { + table.Add("Sectors addressable in sectors in 28-bit LBA mode", $"{testedMedia.LBASectors}"); + + if((ulong)testedMedia.LBASectors * testedMedia.BlockSize / 1024 / 1024 > 1000000) + { + table.Add("Medium size in 28-bit LBA mode", + $"{(ulong)testedMedia.LBASectors * testedMedia.BlockSize} bytes, {(ulong)testedMedia.LBASectors * testedMedia.BlockSize / 1000 / 1000 / 1000 / 1000} Tb, {(double)((ulong)testedMedia.LBASectors * testedMedia.BlockSize) / 1024 / 1024 / 1024 / 1024:F2} TiB"); + } + else if((ulong)testedMedia.LBASectors * testedMedia.BlockSize / 1024 / 1024 > 1000) + { + table.Add("Medium size in 28-bit LBA mode", + $"{(ulong)testedMedia.LBASectors * testedMedia.BlockSize} bytes, {(ulong)testedMedia.LBASectors * testedMedia.BlockSize / 1000 / 1000 / 1000} Gb, {(double)((ulong)testedMedia.LBASectors * testedMedia.BlockSize) / 1024 / 1024 / 1024:F2} GiB"); + } + else + { + table.Add("Medium size in 28-bit LBA mode", + $"{(ulong)testedMedia.LBASectors * testedMedia.BlockSize} bytes, {(ulong)testedMedia.LBASectors * testedMedia.BlockSize / 1000 / 1000} Mb, {(double)((ulong)testedMedia.LBASectors * testedMedia.BlockSize) / 1024 / 1024:F2} MiB"); + } + } + + if(testedMedia.LBA48Sectors != null) + { + table.Add("Sectors addressable in sectors in 48-bit LBA mode", $"{testedMedia.LBA48Sectors}"); + + if(testedMedia.LBA48Sectors * testedMedia.BlockSize / 1024 / 1024 > 1000000) + { + table.Add("Medium size in 48-bit LBA mode", + $"{testedMedia.LBA48Sectors * testedMedia.BlockSize} bytes, {testedMedia.LBA48Sectors * testedMedia.BlockSize / 1000 / 1000 / 1000 / 1000} Tb, {(double)(testedMedia.LBA48Sectors * testedMedia.BlockSize) / 1024 / 1024 / 1024 / 1024:F2} TiB"); + } + else if(testedMedia.LBA48Sectors * testedMedia.BlockSize / 1024 / 1024 > 1000) + { + table.Add("Medium size in 48-bit LBA mode", + $"{testedMedia.LBA48Sectors * testedMedia.BlockSize} bytes, {testedMedia.LBA48Sectors * testedMedia.BlockSize / 1000 / 1000 / 1000} Gb, {(double)(testedMedia.LBA48Sectors * testedMedia.BlockSize) / 1024 / 1024 / 1024:F2} GiB"); + } + else + { + table.Add("Medium size in 48-bit LBA mode", + $"{testedMedia.LBA48Sectors * testedMedia.BlockSize} bytes, {testedMedia.LBA48Sectors * testedMedia.BlockSize / 1000 / 1000} Mb, {(double)(testedMedia.LBA48Sectors * testedMedia.BlockSize) / 1024 / 1024:F2} MiB"); + } + } + + if(testedMedia.NominalRotationRate != null && + testedMedia.NominalRotationRate != 0x0000 && + testedMedia.NominalRotationRate != 0xFFFF) + { + list.Add(testedMedia.NominalRotationRate == 0x0001 + ? "Medium does not rotate." + : $"Medium rotates at {testedMedia.NominalRotationRate} rpm"); + } + + if(testedMedia.BlockSize != null && + testedMedia.PhysicalBlockSize != null && + testedMedia.BlockSize.Value != testedMedia.PhysicalBlockSize.Value && + (testedMedia.LogicalAlignment & 0x8000) == 0x0000 && + (testedMedia.LogicalAlignment & 0x4000) == 0x4000) + list.Add($"Logical sector starts at offset {testedMedia.LogicalAlignment & 0x3FFF} from physical sector"); + + if(testedMedia.SupportsReadSectors == true) + list.Add("Device can use the READ SECTOR(S) command in CHS mode with this medium"); + + if(testedMedia.SupportsReadRetry == true) + list.Add("Device can use the READ SECTOR(S) RETRY command in CHS mode with this medium"); + + if(testedMedia.SupportsReadDma == true) + list.Add("Device can use the READ DMA command in CHS mode with this medium"); + + if(testedMedia.SupportsReadDmaRetry == true) + list.Add("Device can use the READ DMA RETRY command in CHS mode with this medium"); + + if(testedMedia.SupportsReadLong == true) + list.Add("Device can use the READ LONG command in CHS mode with this medium"); + + if(testedMedia.SupportsReadLongRetry == true) + list.Add("Device can use the READ LONG RETRY command in CHS mode with this medium"); + + if(testedMedia.SupportsReadLba == true) + list.Add("Device can use the READ SECTOR(S) command in 28-bit LBA mode with this medium"); + + if(testedMedia.SupportsReadRetryLba == true) + list.Add("Device can use the READ SECTOR(S) RETRY command in 28-bit LBA mode with this medium"); + + if(testedMedia.SupportsReadDmaLba == true) + list.Add("Device can use the READ DMA command in 28-bit LBA mode with this medium"); + + if(testedMedia.SupportsReadDmaRetryLba == true) + list.Add("Device can use the READ DMA RETRY command in 28-bit LBA mode with this medium"); + + if(testedMedia.SupportsReadLongLba == true) + list.Add("Device can use the READ LONG command in 28-bit LBA mode with this medium"); + + if(testedMedia.SupportsReadLongRetryLba == true) + list.Add("Device can use the READ LONG RETRY command in 28-bit LBA mode with this medium"); + + if(testedMedia.SupportsReadLba48 == true) + list.Add("Device can use the READ SECTOR(S) command in 48-bit LBA mode with this medium"); + + if(testedMedia.SupportsReadDmaLba48 == true) + list.Add("Device can use the READ DMA command in 48-bit LBA mode with this medium"); + + if(testedMedia.SupportsSeek == true) + list.Add("Device can use the SEEK command in CHS mode with this medium"); + + if(testedMedia.SupportsSeekLba == true) + list.Add("Device can use the SEEK command in 28-bit LBA mode with this medium"); + + if(testedMedia.SupportsReadCapacity == true) + list.Add("Device can use the READ CAPACITY (10) command with this medium"); + + if(testedMedia.SupportsReadCapacity16 == true) + list.Add("Device can use the READ CAPACITY (16) command with this medium"); + + if(testedMedia.SupportsRead6 == true) list.Add("Device can use the READ (6) command with this medium"); + + if(testedMedia.SupportsRead10 == true) list.Add("Device can use the READ (10) command with this medium"); + + if(testedMedia.SupportsRead12 == true) list.Add("Device can use the READ (12) command with this medium"); + + if(testedMedia.SupportsRead16 == true) list.Add("Device can use the READ (16) command with this medium"); + + if(testedMedia.SupportsReadLong == true) + list.Add("Device can use the READ LONG (10) command with this medium"); + + if(testedMedia.SupportsReadLong16 == true) + list.Add("Device can use the READ LONG (16) command with this medium"); + + if(testedMedia.SupportsReadCd == true) + list.Add("Device can use the READ CD command with LBA addressing with this medium"); + + if(testedMedia.SupportsReadCdMsf == true) + list.Add("Device can use the READ CD command with MM:SS:FF addressing with this medium"); + + if(testedMedia.SupportsReadCdRaw == true) + list.Add("Device can use the READ CD command with LBA addressing with this medium to read raw sector"); + + if(testedMedia.SupportsReadCdMsfRaw == true) + list.Add("Device can use the READ CD command with MM:SS:FF addressing with this medium read raw sector"); + + if(testedMedia.SupportsHLDTSTReadRawDVD == true) + list.Add("Device can use the HL-DT-ST vendor READ DVD (RAW) command with this medium"); + + if(testedMedia.SupportsNECReadCDDA == true) + list.Add("Device can use the NEC vendor READ CD-DA command with this medium"); + + if(testedMedia.SupportsPioneerReadCDDA == true) + list.Add("Device can use the PIONEER vendor READ CD-DA command with this medium"); + + if(testedMedia.SupportsPioneerReadCDDAMSF == true) + list.Add("Device can use the PIONEER vendor READ CD-DA MSF command with this medium"); + + if(testedMedia.SupportsPlextorReadCDDA == true) + list.Add("Device can use the PLEXTOR vendor READ CD-DA command with this medium"); + + if(testedMedia.SupportsPlextorReadRawDVD == true) + list.Add("Device can use the PLEXTOR vendor READ DVD (RAW) command with this medium"); + + if(testedMedia.CanReadAACS == true) + list.Add("Device can read the Advanced Access Content System from this medium"); + + if(testedMedia.CanReadADIP == true) + list.Add("Device can read the DVD ADress-In-Pregroove from this medium"); + + if(testedMedia.CanReadATIP == true) + list.Add("Device can read the CD Absolute-Time-In-Pregroove from this medium"); + + if(testedMedia.CanReadBCA == true) list.Add("Device can read the Burst Cutting Area from this medium"); + + if(testedMedia.CanReadC2Pointers == true) + list.Add("Device can report the C2 pointers when reading from this medium"); + + if(testedMedia.CanReadCMI == true) + list.Add("Device can read the Copyright Management Information from this medium"); + + if(testedMedia.CanReadCorrectedSubchannel == true) + list.Add("Device can correct subchannels when reading from this medium"); + + if(testedMedia.CanReadCorrectedSubchannelWithC2 == true) + list.Add("Device can correct subchannels and report the C2 pointers when reading from this medium"); + + if(testedMedia.CanReadDCB == true) list.Add("Device can read the Disc Control Blocks from this medium"); + + if(testedMedia.CanReadDDS == true) + list.Add("Device can read the Disc Definition Structure from this medium"); + + if(testedMedia.CanReadDMI == true) + list.Add("Device can read the Disc Manufacturer Information from this medium"); + + if(testedMedia.CanReadDiscInformation == true) + list.Add("Device can read the Disc Information from this medium"); + + if(testedMedia.CanReadFullTOC == true) + list.Add("Device can read the Table of Contents from this medium, without processing it"); + + if(testedMedia.CanReadHDCMI == true) + list.Add("Device can read the HD DVD Copyright Management Information from this medium"); + + if(testedMedia.CanReadLayerCapacity == true) + list.Add("Device can read the layer capacity from this medium"); + + if(testedMedia.CanReadFirstTrackPreGap == true) list.Add("Device can read the first track's pregap data"); + + if(testedMedia.CanReadLeadIn == true) list.Add("Device can read the Lead-In from this medium"); + + if(testedMedia.CanReadLeadOut == true) list.Add("Device can read the Lead-Out from this medium"); + + if(testedMedia.CanReadMediaID == true) list.Add("Device can read the Media ID from this medium"); + + if(testedMedia.CanReadMediaSerial == true) + list.Add("Device can read the Media Serial Number from this medium"); + + if(testedMedia.CanReadPAC == true) list.Add("Device can read the PAC from this medium"); + + if(testedMedia.CanReadPFI == true) + list.Add("Device can read the Physical Format Information from this medium"); + + if(testedMedia.CanReadPMA == true) list.Add("Device can read the Power Management Area from this medium"); + + if(testedMedia.CanReadPQSubchannel == true) + list.Add("Device can read the P to Q subchannels from this medium"); + + if(testedMedia.CanReadPQSubchannelWithC2 == true) + list.Add("Device can read the P to Q subchannels from this medium reporting the C2 pointers"); + + if(testedMedia.CanReadPRI == true) + list.Add("Device can read the Pre-Recorded Information from this medium"); + + if(testedMedia.CanReadRWSubchannel == true) + list.Add("Device can read the R to W subchannels from this medium"); + + if(testedMedia.CanReadRWSubchannelWithC2 == true) + list.Add("Device can read the R to W subchannels from this medium reporting the C2 pointers"); + + if(testedMedia.CanReadRecordablePFI == true) + list.Add("Device can read the Physical Format Information from Lead-In from this medium"); + + if(testedMedia.CanReadSpareAreaInformation == true) + list.Add("Device can read the Spare Area Information from this medium"); + + if(testedMedia.CanReadTOC == true) list.Add("Device can read the Table of Contents from this medium"); + + if(testedMedia.CanReadingIntersessionLeadIn == true) list.Add("Device can read Lead-In between sessions"); + + if(testedMedia.CanReadingIntersessionLeadOut == true) list.Add("Device can read Lead-Out between sessions"); + + if(testedMedia.CanReadCdScrambled == true) + list.Add("Device can read scrambled sectors using standard READ CD command"); + + if(testedMedia.CanReadF1_06 == true) + list.Add("Device can read from cache using F1h command with subcommand 06h"); + + if(testedMedia.CanReadF1_06LeadOut == true) + list.Add("Device can read Lead-Out from cache using F1h command with subcommand 06h"); + + mediaInformation.Add(header, (table, list)); + } + } +} \ No newline at end of file