From 6a491e9a1e0894a41d80cdce7d9170d315f05e34 Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Mon, 6 May 2024 03:54:31 +0100 Subject: [PATCH] Add ATA/ATAPI to device report view. --- Aaru.Server.New/Aaru.Server.New.csproj | 2 + .../Components/Pages/Report/View.razor | 29 + .../Components/Pages/Report/View.razor.cs | 49 + Aaru.Server.New/Core/Ata.cs | 1820 +++++++++++++++++ 4 files changed, 1900 insertions(+) create mode 100644 Aaru.Server.New/Core/Ata.cs diff --git a/Aaru.Server.New/Aaru.Server.New.csproj b/Aaru.Server.New/Aaru.Server.New.csproj index afaf28c0..c3877dc4 100644 --- a/Aaru.Server.New/Aaru.Server.New.csproj +++ b/Aaru.Server.New/Aaru.Server.New.csproj @@ -8,6 +8,8 @@ + + diff --git a/Aaru.Server.New/Components/Pages/Report/View.razor b/Aaru.Server.New/Components/Pages/Report/View.razor index 3bca92a4..b8cc76e2 100644 --- a/Aaru.Server.New/Components/Pages/Report/View.razor +++ b/Aaru.Server.New/Components/Pages/Report/View.razor @@ -138,4 +138,33 @@ } + @if(AtaItem != null) + { + + + + @AtaItem characteristics + + + + + @lblAtaDeviceType
+
+ @foreach(KeyValuePair kvp in AtaTwo!) + { + + @kvp.Key: @kvp.Value +
+
+ } +
+ @foreach(string item in AtaOne!) + { + + @item
+
+ } +
+
+ } \ 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 1d3d41cb..12e0a7c3 100644 --- a/Aaru.Server.New/Components/Pages/Report/View.razor.cs +++ b/Aaru.Server.New/Components/Pages/Report/View.razor.cs @@ -1,3 +1,4 @@ +using Aaru.CommonTypes.Metadata; using Aaru.Decoders.PCMCIA; using Aaru.Server.Database.Models; using Microsoft.AspNetCore.Components; @@ -25,6 +26,14 @@ public partial class View public PcmciaItem? PcmciaItem { get; set; } + public Dictionary? AtaTwo { get; set; } + + public List? AtaOne { get; set; } + + public string? lblAtaDeviceType { get; set; } + + public string? AtaItem { get; set; } + /// protected override async Task OnInitializedAsync() { @@ -45,6 +54,8 @@ public partial class View Device? report = await ctx.Devices.Include(static deviceReportV2 => deviceReportV2.USB) .Include(static deviceReportV2 => deviceReportV2.FireWire) .Include(static deviceReportV2 => deviceReportV2.PCMCIA) + .Include(static deviceReportV2 => deviceReportV2.ATAPI) + .Include(static deviceReportV2 => deviceReportV2.ATA) .FirstOrDefaultAsync(d => d.Id == Id); if(report is null) @@ -202,6 +213,44 @@ public partial class View } } + var removable = true; + List? testedMedia; + var atapi = false; + + if(report.ATA != null || report.ATAPI != null) + { + List ataOneValue = []; + Dictionary ataTwoValue = new(); + Ata? ataReport; + + if(report.ATAPI != null) + { + AtaItem = "ATAPI"; + ataReport = report.ATAPI; + atapi = true; + } + else + { + AtaItem = "ATA"; + ataReport = report.ATA; + } + + bool cfa = report.CompactFlash; + + lblAtaDeviceType = atapi switch + { + true when !cfa => "ATAPI device", + false when cfa => "CompactFlash device", + _ => "ATA device" + }; + + Core.Ata.Report(ataReport!, cfa, atapi, ref removable, ataOneValue, ataTwoValue, out testedMedia); + + AtaOne = ataOneValue; + AtaTwo = ataTwoValue; + } + + _initialized = true; StateHasChanged(); diff --git a/Aaru.Server.New/Core/Ata.cs b/Aaru.Server.New/Core/Ata.cs new file mode 100644 index 00000000..e19b9335 --- /dev/null +++ b/Aaru.Server.New/Core/Ata.cs @@ -0,0 +1,1820 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Ata.cs +// Author(s) : Natalia Portillo +// +// Component : Aaru Server. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes ATA information 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; +using Aaru.CommonTypes.Structs.Devices.ATA; +using Aaru.CommonTypes.Structs.Devices.SCSI; + +namespace Aaru.Server.New.Core; + +// TODO: Use Humanizer +// TODO: Better use HTML and CSS +public static class Ata +{ + /// + /// Takes the ATA part of a device report and prints it as a list of values and another list of key=value pairs to + /// be sequenced by ASP.NET in the rendering + /// + /// ATA part of a device report + /// true if compact flash device + /// true if atapi device + /// true if removable device + /// List to put values on + /// List to put key=value pairs on + /// List of tested media + public static void Report(CommonTypes.Metadata.Ata ataReport, bool cfa, bool atapi, ref bool removable, + List ataOneValue, Dictionary ataTwoValue, + out List? testedMedia) + { + uint logicalSectorSize = 0; + testedMedia = null; + + Identify.IdentifyDevice? ataIdentifyNullable = Identify.Decode(ataReport.Identify); + + if(!ataIdentifyNullable.HasValue) return; + + Identify.IdentifyDevice ataIdentify = ataIdentifyNullable.Value; + + if(!string.IsNullOrEmpty(ataIdentify.Model)) ataTwoValue.Add("Model", ataIdentify.Model); + + if(!string.IsNullOrEmpty(ataIdentify.FirmwareRevision)) + ataTwoValue.Add("Firmware revision", ataIdentify.FirmwareRevision); + + if(!string.IsNullOrEmpty(ataIdentify.AdditionalPID)) + ataTwoValue.Add("Additional product ID", ataIdentify.AdditionalPID); + + if(!atapi) + { + logicalSectorSize = ataIdentify.LogicalSectorWords * 2; + + if(logicalSectorSize is 0) logicalSectorSize = 512; + + // Multiple logical sectors per physical sector + if((ataIdentify.PhysLogSectorSize & 0xD000) == 0x5000) + logicalSectorSize *= (uint)(1 << (ataIdentify.PhysLogSectorSize & 0x0F)); + } + + bool ata1 = false, + ata2 = false, + ata3 = false, + ata4 = false, + ata5 = false, + ata6 = false, + ata7 = false, + acs = false, + acs2 = false, + acs3 = false, + acs4 = false; + + if((ushort)ataIdentify.MajorVersion == 0x0000 || (ushort)ataIdentify.MajorVersion == 0xFFFF) + { + // Obsolete in ATA-2, if present, device supports ATA-1 + ata1 |= ataIdentify.GeneralConfiguration.HasFlag(Identify.GeneralConfigurationBit.FastIDE) || + ataIdentify.GeneralConfiguration.HasFlag(Identify.GeneralConfigurationBit.SlowIDE) || + ataIdentify.GeneralConfiguration.HasFlag(Identify.GeneralConfigurationBit.UltraFastIDE); + + ata2 |= ataIdentify.ExtendedIdentify.HasFlag(Identify.ExtendedIdentifyBit.Words54to58Valid) || + ataIdentify.ExtendedIdentify.HasFlag(Identify.ExtendedIdentifyBit.Words64to70Valid) || + ataIdentify.ExtendedIdentify.HasFlag(Identify.ExtendedIdentifyBit.Word88Valid); + + if(!ata1 && !ata2 && !atapi && !cfa) ata2 = true; + + ata4 |= atapi; + ata3 |= cfa; + + if(cfa && ata1) ata1 = false; + + if(cfa && ata2) ata2 = false; + } + else + { + ata1 |= ataIdentify.MajorVersion.HasFlag(Identify.MajorVersionBit.Ata1); + ata2 |= ataIdentify.MajorVersion.HasFlag(Identify.MajorVersionBit.Ata2); + ata3 |= ataIdentify.MajorVersion.HasFlag(Identify.MajorVersionBit.Ata3); + ata4 |= ataIdentify.MajorVersion.HasFlag(Identify.MajorVersionBit.AtaAtapi4); + ata5 |= ataIdentify.MajorVersion.HasFlag(Identify.MajorVersionBit.AtaAtapi5); + ata6 |= ataIdentify.MajorVersion.HasFlag(Identify.MajorVersionBit.AtaAtapi6); + ata7 |= ataIdentify.MajorVersion.HasFlag(Identify.MajorVersionBit.AtaAtapi7); + acs |= ataIdentify.MajorVersion.HasFlag(Identify.MajorVersionBit.Ata8ACS); + acs2 |= ataIdentify.MajorVersion.HasFlag(Identify.MajorVersionBit.ACS2); + acs3 |= ataIdentify.MajorVersion.HasFlag(Identify.MajorVersionBit.ACS3); + acs4 |= ataIdentify.MajorVersion.HasFlag(Identify.MajorVersionBit.ACS4); + } + + var maxAtaLevel = 0; + var minAtaLevel = 255; + var tmpString = ""; + + if(ata1) + { + tmpString += "ATA-1 "; + maxAtaLevel = 1; + minAtaLevel = 1; + } + + if(ata2) + { + tmpString += "ATA-2 "; + maxAtaLevel = 2; + + if(minAtaLevel > 2) minAtaLevel = 2; + } + + if(ata3) + { + tmpString += "ATA-3 "; + maxAtaLevel = 3; + + if(minAtaLevel > 3) minAtaLevel = 3; + } + + if(ata4) + { + tmpString += "ATA/ATAPI-4 "; + maxAtaLevel = 4; + + if(minAtaLevel > 4) minAtaLevel = 4; + } + + if(ata5) + { + tmpString += "ATA/ATAPI-5 "; + maxAtaLevel = 5; + + if(minAtaLevel > 5) minAtaLevel = 5; + } + + if(ata6) + { + tmpString += "ATA/ATAPI-6 "; + maxAtaLevel = 6; + + if(minAtaLevel > 6) minAtaLevel = 6; + } + + if(ata7) + { + tmpString += "ATA/ATAPI-7 "; + maxAtaLevel = 7; + + if(minAtaLevel > 7) minAtaLevel = 7; + } + + if(acs) + { + tmpString += "ATA8-ACS "; + maxAtaLevel = 8; + + if(minAtaLevel > 8) minAtaLevel = 8; + } + + if(acs2) + { + tmpString += "ATA8-ACS2 "; + maxAtaLevel = 9; + + if(minAtaLevel > 9) minAtaLevel = 9; + } + + if(acs3) + { + tmpString += "ATA8-ACS3 "; + maxAtaLevel = 10; + + if(minAtaLevel > 10) minAtaLevel = 10; + } + + if(acs4) + { + tmpString += "ATA8-ACS4 "; + maxAtaLevel = 11; + + if(minAtaLevel > 11) minAtaLevel = 11; + } + + if(tmpString != "") ataTwoValue.Add("Supported ATA versions", tmpString); + + if(maxAtaLevel >= 3) + { + tmpString = ataIdentify.MinorVersion switch + { + 0x0000 or 0xFFFF => "Minor ATA version not specified", + 0x0001 => "ATA (ATA-1) X3T9.2 781D prior to revision 4", + 0x0002 => "ATA-1 published, ANSI X3.221-1994", + 0x0003 => "ATA (ATA-1) X3T9.2 781D revision 4", + 0x0004 => "ATA-2 published, ANSI X3.279-1996", + 0x0005 => "ATA-2 X3T10 948D prior to revision 2k", + 0x0006 => "ATA-3 X3T10 2008D revision 1", + 0x0007 => "ATA-2 X3T10 948D revision 2k", + 0x0008 => "ATA-3 X3T10 2008D revision 0", + 0x0009 => "ATA-2 X3T10 948D revision 3", + 0x000A => "ATA-3 published, ANSI X3.298-1997", + 0x000B => "ATA-3 X3T10 2008D revision 6", + 0x000C => "ATA-3 X3T13 2008D revision 7", + 0x000D => "ATA/ATAPI-4 X3T13 1153D revision 6", + 0x000E => "ATA/ATAPI-4 T13 1153D revision 13", + 0x000F => "ATA/ATAPI-4 X3T13 1153D revision 7", + 0x0010 => "ATA/ATAPI-4 T13 1153D revision 18", + 0x0011 => "ATA/ATAPI-4 T13 1153D revision 15", + 0x0012 => "ATA/ATAPI-4 published, ANSI INCITS 317-1998", + 0x0013 => "ATA/ATAPI-5 T13 1321D revision 3", + 0x0014 => "ATA/ATAPI-4 T13 1153D revision 14", + 0x0015 => "ATA/ATAPI-5 T13 1321D revision 1", + 0x0016 => "ATA/ATAPI-5 published, ANSI INCITS 340-2000", + 0x0017 => "ATA/ATAPI-4 T13 1153D revision 17", + 0x0018 => "ATA/ATAPI-6 T13 1410D revision 0", + 0x0019 => "ATA/ATAPI-6 T13 1410D revision 3a", + 0x001A => "ATA/ATAPI-7 T13 1532D revision 1", + 0x001B => "ATA/ATAPI-6 T13 1410D revision 2", + 0x001C => "ATA/ATAPI-6 T13 1410D revision 1", + 0x001D => "ATA/ATAPI-7 published ANSI INCITS 397-2005", + 0x001E => "ATA/ATAPI-7 T13 1532D revision 0", + 0x001F => "ACS-3 Revision 3b", + 0x0021 => "ATA/ATAPI-7 T13 1532D revision 4a", + 0x0022 => "ATA/ATAPI-6 published, ANSI INCITS 361-2002", + 0x0027 => "ATA8-ACS revision 3c", + 0x0028 => "ATA8-ACS revision 6", + 0x0029 => "ATA8-ACS revision 4", + 0x0031 => "ACS-2 Revision 2", + 0x0033 => "ATA8-ACS Revision 3e", + 0x0039 => "ATA8-ACS Revision 4c", + 0x0042 => "ATA8-ACS Revision 3f", + 0x0052 => "ATA8-ACS revision 3b", + 0x006D => "ACS-3 Revision 5", + 0x0082 => "ACS-2 published, ANSI INCITS 482-2012", + 0x0107 => "ATA8-ACS revision 2d", + 0x0110 => "ACS-2 Revision 3", + 0x011B => "ACS-3 Revision 4", + _ => $"Unknown ATA revision 0x{ataIdentify.MinorVersion:X4}" + }; + + ataTwoValue.Add("Maximum ATA revision supported", tmpString); + } + + tmpString = ""; + + switch((ataIdentify.TransportMajorVersion & 0xF000) >> 12) + { + case 0x0: + if((ataIdentify.TransportMajorVersion & 0x0002) == 0x0002) tmpString += "ATA/ATAPI-7 "; + + if((ataIdentify.TransportMajorVersion & 0x0001) == 0x0001) tmpString += "ATA8-APT "; + + ataTwoValue.Add("Parallel ATA device", tmpString); + + break; + case 0x1: + if((ataIdentify.TransportMajorVersion & 0x0001) == 0x0001) tmpString += "ATA8-AST "; + + if((ataIdentify.TransportMajorVersion & 0x0002) == 0x0002) tmpString += "SATA 1.0a "; + + if((ataIdentify.TransportMajorVersion & 0x0004) == 0x0004) tmpString += "SATA II Extensions "; + + if((ataIdentify.TransportMajorVersion & 0x0008) == 0x0008) tmpString += "SATA 2.5 "; + + if((ataIdentify.TransportMajorVersion & 0x0010) == 0x0010) tmpString += "SATA 2.6 "; + + if((ataIdentify.TransportMajorVersion & 0x0020) == 0x0020) tmpString += "SATA 3.0 "; + + if((ataIdentify.TransportMajorVersion & 0x0040) == 0x0040) tmpString += "SATA 3.1 "; + + ataTwoValue.Add("Serial ATA device: ", tmpString); + + break; + case 0xE: + ataTwoValue.Add("SATA Express device", "No version"); + + break; + default: + ataTwoValue.Add("Unknown transport type", $"0x{(ataIdentify.TransportMajorVersion & 0xF000) >> 12:X1}"); + + break; + } + + if(atapi) + { + // Bits 12 to 8, SCSI Peripheral Device Type + switch((PeripheralDeviceTypes)(((ushort)ataIdentify.GeneralConfiguration & 0x1F00) >> 8)) + { + case PeripheralDeviceTypes.DirectAccess: //0x00, + ataOneValue.Add("ATAPI Direct-access device"); + + break; + case PeripheralDeviceTypes.SequentialAccess: //0x01, + ataOneValue.Add("ATAPI Sequential-access device"); + + break; + case PeripheralDeviceTypes.PrinterDevice: //0x02, + ataOneValue.Add("ATAPI Printer device"); + + break; + case PeripheralDeviceTypes.ProcessorDevice: //0x03, + ataOneValue.Add("ATAPI Processor device"); + + break; + case PeripheralDeviceTypes.WriteOnceDevice: //0x04, + ataOneValue.Add("ATAPI Write-once device"); + + break; + case PeripheralDeviceTypes.MultiMediaDevice: //0x05, + ataOneValue.Add("ATAPI CD-ROM/DVD/etc device"); + + break; + case PeripheralDeviceTypes.ScannerDevice: //0x06, + ataOneValue.Add("ATAPI Scanner device"); + + break; + case PeripheralDeviceTypes.OpticalDevice: //0x07, + ataOneValue.Add("ATAPI Optical memory device"); + + break; + case PeripheralDeviceTypes.MediumChangerDevice: //0x08, + ataOneValue.Add("ATAPI Medium change device"); + + break; + case PeripheralDeviceTypes.CommsDevice: //0x09, + ataOneValue.Add("ATAPI Communications device"); + + break; + case PeripheralDeviceTypes.PrePressDevice1: //0x0A, + ataOneValue.Add("ATAPI Graphics arts pre-press device (defined in ASC IT8)"); + + break; + case PeripheralDeviceTypes.PrePressDevice2: //0x0B, + ataOneValue.Add("ATAPI Graphics arts pre-press device (defined in ASC IT8)"); + + break; + case PeripheralDeviceTypes.ArrayControllerDevice: //0x0C, + ataOneValue.Add("ATAPI Array controller device"); + + break; + case PeripheralDeviceTypes.EnclosureServiceDevice: //0x0D, + ataOneValue.Add("ATAPI Enclosure services device"); + + break; + case PeripheralDeviceTypes.SimplifiedDevice: //0x0E, + ataOneValue.Add("ATAPI Simplified direct-access device"); + + break; + case PeripheralDeviceTypes.OCRWDevice: //0x0F, + ataOneValue.Add("ATAPI Optical card reader/writer device"); + + break; + case PeripheralDeviceTypes.BridgingExpander: //0x10, + ataOneValue.Add("ATAPI Bridging Expanders"); + + break; + case PeripheralDeviceTypes.ObjectDevice: //0x11, + ataOneValue.Add("ATAPI Object-based Storage Device"); + + break; + case PeripheralDeviceTypes.ADCDevice: //0x12, + ataOneValue.Add("ATAPI Automation/Drive Interface"); + + break; + case PeripheralDeviceTypes.WellKnownDevice: //0x1E, + ataOneValue.Add("ATAPI Well known logical unit"); + + break; + case PeripheralDeviceTypes.UnknownDevice: //0x1F + ataOneValue.Add("ATAPI Unknown or no device type"); + + break; + default: + ataOneValue + .Add($"ATAPI Unknown device type field value 0x{((ushort)ataIdentify.GeneralConfiguration & 0x1F00) >> 8:X2}"); + + break; + } + + // ATAPI DRQ behaviour + switch(((ushort)ataIdentify.GeneralConfiguration & 0x60) >> 5) + { + case 0: + ataOneValue.Add("Device shall set DRQ within 3 ms of receiving PACKET"); + + break; + case 1: + ataOneValue.Add("Device shall assert INTRQ when DRQ is set to one"); + + break; + case 2: + ataOneValue.Add("Device shall set DRQ within 50 µs of receiving PACKET"); + + break; + default: + ataOneValue + .Add($"Unknown ATAPI DRQ behaviour code {((ushort)ataIdentify.GeneralConfiguration & 0x60) >> 5}"); + + break; + } + + // ATAPI PACKET size + switch((ushort)ataIdentify.GeneralConfiguration & 0x03) + { + case 0: + ataOneValue.Add("ATAPI device uses 12 byte command packet"); + + break; + case 1: + ataOneValue.Add("ATAPI device uses 16 byte command packet"); + + break; + default: + ataOneValue + .Add($"Unknown ATAPI packet size code {(ushort)ataIdentify.GeneralConfiguration & 0x03}"); + + break; + } + } + else if(!cfa) + { + if(minAtaLevel >= 5) + { + if(ataIdentify.GeneralConfiguration.HasFlag(Identify.GeneralConfigurationBit.IncompleteResponse)) + ataOneValue.Add("Incomplete identify response"); + } + + if(ataIdentify.GeneralConfiguration.HasFlag(Identify.GeneralConfigurationBit.NonMagnetic)) + ataOneValue.Add("Device uses non-magnetic media"); + + if(ataIdentify.GeneralConfiguration.HasFlag(Identify.GeneralConfigurationBit.Removable)) + ataOneValue.Add("Device is removable"); + + if(minAtaLevel <= 5) + { + if(ataIdentify.GeneralConfiguration.HasFlag(Identify.GeneralConfigurationBit.Fixed)) + ataOneValue.Add("Device is fixed"); + } + + if(ata1) + { + if(ataIdentify.GeneralConfiguration.HasFlag(Identify.GeneralConfigurationBit.SlowIDE)) + ataOneValue.Add("Device transfer rate is <= 5 Mb/s"); + + if(ataIdentify.GeneralConfiguration.HasFlag(Identify.GeneralConfigurationBit.FastIDE)) + ataOneValue.Add("Device transfer rate is > 5 Mb/s but <= 10 Mb/s"); + + if(ataIdentify.GeneralConfiguration.HasFlag(Identify.GeneralConfigurationBit.UltraFastIDE)) + ataOneValue.Add("Device transfer rate is > 10 Mb/s"); + + if(ataIdentify.GeneralConfiguration.HasFlag(Identify.GeneralConfigurationBit.SoftSector)) + ataOneValue.Add("Device is soft sectored"); + + if(ataIdentify.GeneralConfiguration.HasFlag(Identify.GeneralConfigurationBit.HardSector)) + ataOneValue.Add("Device is hard sectored"); + + if(ataIdentify.GeneralConfiguration.HasFlag(Identify.GeneralConfigurationBit.NotMFM)) + ataOneValue.Add("Device is not MFM encoded"); + + if(ataIdentify.GeneralConfiguration.HasFlag(Identify.GeneralConfigurationBit.FormatGapReq)) + ataOneValue.Add("Format speed tolerance gap is required"); + + if(ataIdentify.GeneralConfiguration.HasFlag(Identify.GeneralConfigurationBit.TrackOffset)) + ataOneValue.Add("Track offset option is available"); + + if(ataIdentify.GeneralConfiguration.HasFlag(Identify.GeneralConfigurationBit.DataStrobeOffset)) + ataOneValue.Add("Data strobe offset option is available"); + + if(ataIdentify.GeneralConfiguration.HasFlag(Identify.GeneralConfigurationBit.RotationalSpeedTolerance)) + ataOneValue.Add("Rotational speed tolerance is higher than 0,5%"); + + if(ataIdentify.GeneralConfiguration.HasFlag(Identify.GeneralConfigurationBit.SpindleControl)) + ataOneValue.Add("Spindle motor control is implemented"); + + if(ataIdentify.GeneralConfiguration.HasFlag(Identify.GeneralConfigurationBit.HighHeadSwitch)) + ataOneValue.Add("Head switch time is bigger than 15 µs."); + } + } + + if((ushort)ataIdentify.SpecificConfiguration != 0x0000 && (ushort)ataIdentify.SpecificConfiguration != 0xFFFF) + { + switch(ataIdentify.SpecificConfiguration) + { + case Identify.SpecificConfigurationEnum.RequiresSetIncompleteResponse: + ataOneValue + .Add("Device requires SET FEATURES to spin up and IDENTIFY DEVICE response is incomplete."); + + break; + case Identify.SpecificConfigurationEnum.RequiresSetCompleteResponse: + ataOneValue + .Add("Device requires SET FEATURES to spin up and IDENTIFY DEVICE response is complete."); + + break; + case Identify.SpecificConfigurationEnum.NotRequiresSetIncompleteResponse: + ataOneValue + .Add("Device does not require SET FEATURES to spin up and IDENTIFY DEVICE response is incomplete."); + + break; + case Identify.SpecificConfigurationEnum.NotRequiresSetCompleteResponse: + ataOneValue + .Add("Device does not require SET FEATURES to spin up and IDENTIFY DEVICE response is complete."); + + break; + default: + ataOneValue + .Add($"Unknown device specific configuration 0x{(ushort)ataIdentify.SpecificConfiguration:X4}"); + + break; + } + } + + // Obsolete since ATA-2, however, it is yet used in ATA-8 devices + if(ataIdentify.BufferSize != 0x0000 && + ataIdentify.BufferSize != 0xFFFF && + ataIdentify.BufferType != 0x0000 && + ataIdentify.BufferType != 0xFFFF) + { + switch(ataIdentify.BufferType) + { + case 1: + ataOneValue + .Add($"{ataIdentify.BufferSize * logicalSectorSize / 1024} KiB of single ported single sector buffer"); + + break; + case 2: + ataOneValue + .Add($"{ataIdentify.BufferSize * logicalSectorSize / 1024} KiB of dual ported multi sector buffer"); + + break; + case 3: + ataOneValue + .Add($"{ataIdentify.BufferSize * logicalSectorSize / 1024} KiB of dual ported multi sector buffer with read caching"); + + break; + default: + ataOneValue + .Add($"{ataIdentify.BufferSize * logicalSectorSize / 1024} KiB of unknown type {ataIdentify.BufferType} buffer"); + + break; + } + } + + ataOneValue.Add("Device capabilities:"); + + if(ataIdentify.Capabilities.HasFlag(Identify.CapabilitiesBit.StandardStandbyTimer)) + ataOneValue.Add("Standby time values are standard"); + + if(ataIdentify.Capabilities.HasFlag(Identify.CapabilitiesBit.IORDY)) + { + ataOneValue.Add(ataIdentify.Capabilities.HasFlag(Identify.CapabilitiesBit.CanDisableIORDY) + ? "IORDY is supported and can be disabled" + : "IORDY is supported"); + } + + if(ataIdentify.Capabilities.HasFlag(Identify.CapabilitiesBit.DMASupport)) ataOneValue.Add("DMA is supported"); + + if(ataIdentify.Capabilities.HasFlag(Identify.CapabilitiesBit.PhysicalAlignment1) || + ataIdentify.Capabilities.HasFlag(Identify.CapabilitiesBit.PhysicalAlignment0)) + ataOneValue.Add($"Long Physical Alignment setting is {(ushort)ataIdentify.Capabilities & 0x03}"); + + if(atapi) + { + if(ataIdentify.Capabilities.HasFlag(Identify.CapabilitiesBit.InterleavedDMA)) + ataOneValue.Add("ATAPI device supports interleaved DMA"); + + if(ataIdentify.Capabilities.HasFlag(Identify.CapabilitiesBit.CommandQueue)) + ataOneValue.Add("ATAPI device supports command queueing"); + + if(ataIdentify.Capabilities.HasFlag(Identify.CapabilitiesBit.OverlapOperation)) + ataOneValue.Add("ATAPI device supports overlapped operations"); + + if(ataIdentify.Capabilities.HasFlag(Identify.CapabilitiesBit.RequiresATASoftReset)) + ataOneValue.Add("ATAPI device requires ATA software reset"); + } + + if(ataIdentify.Capabilities2.HasFlag(Identify.CapabilitiesBit2.MustBeSet) && + !ataIdentify.Capabilities2.HasFlag(Identify.CapabilitiesBit2.MustBeClear)) + { + if(ataIdentify.Capabilities2.HasFlag(Identify.CapabilitiesBit2.SpecificStandbyTimer)) + ataOneValue.Add("Device indicates a specific minimum standby timer value"); + } + + if(ataIdentify.Capabilities3.HasFlag(Identify.CapabilitiesBit3.MultipleValid)) + { + ataOneValue.Add($"A maximum of {ataIdentify.MultipleSectorNumber} sectors can be transferred per interrupt on READ/WRITE MULTIPLE"); + + ataOneValue.Add($"Device supports setting a maximum of {ataIdentify.MultipleMaxSectors} sectors"); + } + + if(ata1) + { + if(ataIdentify.TrustedComputing.HasFlag(Identify.TrustedComputingBit.TrustedComputing)) + ataOneValue.Add("Device supports doubleword I/O"); + } + + if(minAtaLevel <= 3) + { + if(ataIdentify.PIOTransferTimingMode > 0) + ataTwoValue.Add("PIO timing mode", $"{ataIdentify.PIOTransferTimingMode}"); + + if(ataIdentify.DMATransferTimingMode > 0) + ataTwoValue.Add("DMA timing mode", $"{ataIdentify.DMATransferTimingMode}"); + } + + tmpString = ""; + + if(ataIdentify.APIOSupported.HasFlag(Identify.TransferMode.Mode0)) tmpString += "PIO0 "; + + if(ataIdentify.APIOSupported.HasFlag(Identify.TransferMode.Mode1)) tmpString += "PIO1 "; + + if(ataIdentify.APIOSupported.HasFlag(Identify.TransferMode.Mode2)) tmpString += "PIO2 "; + + if(ataIdentify.APIOSupported.HasFlag(Identify.TransferMode.Mode3)) tmpString += "PIO3 "; + + if(ataIdentify.APIOSupported.HasFlag(Identify.TransferMode.Mode4)) tmpString += "PIO4 "; + + if(ataIdentify.APIOSupported.HasFlag(Identify.TransferMode.Mode5)) tmpString += "PIO5 "; + + if(ataIdentify.APIOSupported.HasFlag(Identify.TransferMode.Mode6)) tmpString += "PIO6 "; + + if(ataIdentify.APIOSupported.HasFlag(Identify.TransferMode.Mode7)) tmpString += "PIO7 "; + + if(!string.IsNullOrEmpty(tmpString)) ataTwoValue.Add("Advanced PIO", tmpString); + + if(minAtaLevel <= 3 && !atapi) + { + tmpString = ""; + + if(ataIdentify.DMASupported.HasFlag(Identify.TransferMode.Mode0)) + { + tmpString += "DMA0 "; + + if(ataIdentify.DMAActive.HasFlag(Identify.TransferMode.Mode0)) tmpString += "(active) "; + } + + if(ataIdentify.DMASupported.HasFlag(Identify.TransferMode.Mode1)) + { + tmpString += "DMA1 "; + + if(ataIdentify.DMAActive.HasFlag(Identify.TransferMode.Mode1)) tmpString += "(active) "; + } + + if(ataIdentify.DMASupported.HasFlag(Identify.TransferMode.Mode2)) + { + tmpString += "DMA2 "; + + if(ataIdentify.DMAActive.HasFlag(Identify.TransferMode.Mode2)) tmpString += "(active) "; + } + + if(ataIdentify.DMASupported.HasFlag(Identify.TransferMode.Mode3)) + { + tmpString += "DMA3 "; + + if(ataIdentify.DMAActive.HasFlag(Identify.TransferMode.Mode3)) tmpString += "(active) "; + } + + if(ataIdentify.DMASupported.HasFlag(Identify.TransferMode.Mode4)) + { + tmpString += "DMA4 "; + + if(ataIdentify.DMAActive.HasFlag(Identify.TransferMode.Mode4)) tmpString += "(active) "; + } + + if(ataIdentify.DMASupported.HasFlag(Identify.TransferMode.Mode5)) + { + tmpString += "DMA5 "; + + if(ataIdentify.DMAActive.HasFlag(Identify.TransferMode.Mode5)) tmpString += "(active) "; + } + + if(ataIdentify.DMASupported.HasFlag(Identify.TransferMode.Mode6)) + { + tmpString += "DMA6 "; + + if(ataIdentify.DMAActive.HasFlag(Identify.TransferMode.Mode6)) tmpString += "(active) "; + } + + if(ataIdentify.DMASupported.HasFlag(Identify.TransferMode.Mode7)) + { + tmpString += "DMA7 "; + + if(ataIdentify.DMAActive.HasFlag(Identify.TransferMode.Mode7)) tmpString += "(active) "; + } + + if(!string.IsNullOrEmpty(tmpString)) ataTwoValue.Add("Single-word DMA", tmpString); + } + + tmpString = ""; + + if(ataIdentify.MDMASupported.HasFlag(Identify.TransferMode.Mode0)) + { + tmpString += "MDMA0 "; + + if(ataIdentify.MDMAActive.HasFlag(Identify.TransferMode.Mode0)) tmpString += "(active) "; + } + + if(ataIdentify.MDMASupported.HasFlag(Identify.TransferMode.Mode1)) + { + tmpString += "MDMA1 "; + + if(ataIdentify.MDMAActive.HasFlag(Identify.TransferMode.Mode1)) tmpString += "(active) "; + } + + if(ataIdentify.MDMASupported.HasFlag(Identify.TransferMode.Mode2)) + { + tmpString += "MDMA2 "; + + if(ataIdentify.MDMAActive.HasFlag(Identify.TransferMode.Mode2)) tmpString += "(active) "; + } + + if(ataIdentify.MDMASupported.HasFlag(Identify.TransferMode.Mode3)) + { + tmpString += "MDMA3 "; + + if(ataIdentify.MDMAActive.HasFlag(Identify.TransferMode.Mode3)) tmpString += "(active) "; + } + + if(ataIdentify.MDMASupported.HasFlag(Identify.TransferMode.Mode4)) + { + tmpString += "MDMA4 "; + + if(ataIdentify.MDMAActive.HasFlag(Identify.TransferMode.Mode4)) tmpString += "(active) "; + } + + if(ataIdentify.MDMASupported.HasFlag(Identify.TransferMode.Mode5)) + { + tmpString += "MDMA5 "; + + if(ataIdentify.MDMAActive.HasFlag(Identify.TransferMode.Mode5)) tmpString += "(active) "; + } + + if(ataIdentify.MDMASupported.HasFlag(Identify.TransferMode.Mode6)) + { + tmpString += "MDMA6 "; + + if(ataIdentify.MDMAActive.HasFlag(Identify.TransferMode.Mode6)) tmpString += "(active) "; + } + + if(ataIdentify.MDMASupported.HasFlag(Identify.TransferMode.Mode7)) + { + tmpString += "MDMA7 "; + + if(ataIdentify.MDMAActive.HasFlag(Identify.TransferMode.Mode7)) tmpString += "(active) "; + } + + if(!string.IsNullOrEmpty(tmpString)) ataTwoValue.Add("Multi-word DMA", tmpString); + + tmpString = ""; + + if(ataIdentify.UDMASupported.HasFlag(Identify.TransferMode.Mode0)) + { + tmpString += "UDMA0 "; + + if(ataIdentify.UDMAActive.HasFlag(Identify.TransferMode.Mode0)) tmpString += "(active) "; + } + + if(ataIdentify.UDMASupported.HasFlag(Identify.TransferMode.Mode1)) + { + tmpString += "UDMA1 "; + + if(ataIdentify.UDMAActive.HasFlag(Identify.TransferMode.Mode1)) tmpString += "(active) "; + } + + if(ataIdentify.UDMASupported.HasFlag(Identify.TransferMode.Mode2)) + { + tmpString += "UDMA2 "; + + if(ataIdentify.UDMAActive.HasFlag(Identify.TransferMode.Mode2)) tmpString += "(active) "; + } + + if(ataIdentify.UDMASupported.HasFlag(Identify.TransferMode.Mode3)) + { + tmpString += "UDMA3 "; + + if(ataIdentify.UDMAActive.HasFlag(Identify.TransferMode.Mode3)) tmpString += "(active) "; + } + + if(ataIdentify.UDMASupported.HasFlag(Identify.TransferMode.Mode4)) + { + tmpString += "UDMA4 "; + + if(ataIdentify.UDMAActive.HasFlag(Identify.TransferMode.Mode4)) tmpString += "(active) "; + } + + if(ataIdentify.UDMASupported.HasFlag(Identify.TransferMode.Mode5)) + { + tmpString += "UDMA5 "; + + if(ataIdentify.UDMAActive.HasFlag(Identify.TransferMode.Mode5)) tmpString += "(active) "; + } + + if(ataIdentify.UDMASupported.HasFlag(Identify.TransferMode.Mode6)) + { + tmpString += "UDMA6 "; + + if(ataIdentify.UDMAActive.HasFlag(Identify.TransferMode.Mode6)) tmpString += "(active) "; + } + + if(ataIdentify.UDMASupported.HasFlag(Identify.TransferMode.Mode7)) + { + tmpString += "UDMA7 "; + + if(ataIdentify.UDMAActive.HasFlag(Identify.TransferMode.Mode7)) tmpString += "(active) "; + } + + if(!string.IsNullOrEmpty(tmpString)) ataTwoValue.Add("Ultra DMA", tmpString); + + if(ataIdentify.MinMDMACycleTime != 0 && ataIdentify.RecMDMACycleTime != 0) + { + ataOneValue.Add($"At minimum {ataIdentify.MinMDMACycleTime} ns. transfer cycle time per word in MDMA, " + + $"{ataIdentify.RecMDMACycleTime} ns. recommended"); + } + + if(ataIdentify.MinPIOCycleTimeNoFlow != 0) + { + ataOneValue.Add($"At minimum {ataIdentify.MinPIOCycleTimeNoFlow} ns. transfer cycle time per word in PIO, " + + "without flow control"); + } + + if(ataIdentify.MinPIOCycleTimeFlow != 0) + { + ataOneValue.Add($"At minimum {ataIdentify.MinPIOCycleTimeFlow} ns. transfer cycle time per word in PIO, " + + "with IORDY flow control"); + } + + if(ataIdentify.MaxQueueDepth != 0) ataOneValue.Add($"{ataIdentify.MaxQueueDepth + 1} depth of queue maximum"); + + if(atapi) + { + if(ataIdentify.PacketBusRelease != 0) + ataOneValue.Add($"{ataIdentify.PacketBusRelease} ns. typical to release bus from receipt of PACKET"); + + if(ataIdentify.ServiceBusyClear != 0) + ataOneValue.Add($"{ataIdentify.ServiceBusyClear} ns. typical to clear BSY bit from receipt of SERVICE"); + } + + if((ataIdentify.TransportMajorVersion & 0xF000) >> 12 == 0x1 || + (ataIdentify.TransportMajorVersion & 0xF000) >> 12 == 0xE) + { + if(!ataIdentify.SATACapabilities.HasFlag(Identify.SATACapabilitiesBit.Clear)) + { + if(ataIdentify.SATACapabilities.HasFlag(Identify.SATACapabilitiesBit.Gen1Speed)) + ataOneValue.Add("SATA 1.5Gb/s is supported"); + + if(ataIdentify.SATACapabilities.HasFlag(Identify.SATACapabilitiesBit.Gen2Speed)) + ataOneValue.Add("SATA 3.0Gb/s is supported"); + + if(ataIdentify.SATACapabilities.HasFlag(Identify.SATACapabilitiesBit.Gen3Speed)) + ataOneValue.Add("SATA 6.0Gb/s is supported"); + + if(ataIdentify.SATACapabilities.HasFlag(Identify.SATACapabilitiesBit.PowerReceipt)) + ataOneValue.Add("Receipt of host initiated power management requests is supported"); + + if(ataIdentify.SATACapabilities.HasFlag(Identify.SATACapabilitiesBit.PHYEventCounter)) + ataOneValue.Add("PHY Event counters are supported"); + + if(ataIdentify.SATACapabilities.HasFlag(Identify.SATACapabilitiesBit.HostSlumbTrans)) + ataOneValue.Add("Supports host automatic partial to slumber transitions is supported"); + + if(ataIdentify.SATACapabilities.HasFlag(Identify.SATACapabilitiesBit.DevSlumbTrans)) + ataOneValue.Add("Supports device automatic partial to slumber transitions is supported"); + + if(ataIdentify.SATACapabilities.HasFlag(Identify.SATACapabilitiesBit.NCQ)) + { + ataOneValue.Add("NCQ is supported"); + + if(ataIdentify.SATACapabilities.HasFlag(Identify.SATACapabilitiesBit.NCQPriority)) + ataOneValue.Add("NCQ priority is supported"); + + if(ataIdentify.SATACapabilities.HasFlag(Identify.SATACapabilitiesBit.UnloadNCQ)) + ataOneValue.Add("Unload is supported with outstanding NCQ commands"); + } + } + + if(!ataIdentify.SATACapabilities2.HasFlag(Identify.SATACapabilitiesBit2.Clear)) + { + if(!ataIdentify.SATACapabilities.HasFlag(Identify.SATACapabilitiesBit.Clear) && + ataIdentify.SATACapabilities.HasFlag(Identify.SATACapabilitiesBit.NCQ)) + { + if(ataIdentify.SATACapabilities2.HasFlag(Identify.SATACapabilitiesBit2.NCQMgmt)) + ataOneValue.Add("NCQ queue management is supported"); + + if(ataIdentify.SATACapabilities2.HasFlag(Identify.SATACapabilitiesBit2.NCQStream)) + ataOneValue.Add("NCQ streaming is supported"); + } + + if(atapi) + { + if(ataIdentify.SATACapabilities2.HasFlag(Identify.SATACapabilitiesBit2.HostEnvDetect)) + ataOneValue.Add("ATAPI device supports host environment detection"); + + if(ataIdentify.SATACapabilities2.HasFlag(Identify.SATACapabilitiesBit2.DevAttSlimline)) + ataOneValue.Add("ATAPI device supports attention on slimline connected devices"); + } + } + } + + if(ataIdentify.InterseekDelay != 0x0000 && ataIdentify.InterseekDelay != 0xFFFF) + ataOneValue.Add($"{ataIdentify.InterseekDelay} microseconds of interseek delay for ISO-7779 acoustic testing"); + + if((ushort)ataIdentify.DeviceFormFactor != 0x0000 && (ushort)ataIdentify.DeviceFormFactor != 0xFFFF) + { + switch(ataIdentify.DeviceFormFactor) + { + case Identify.DeviceFormFactorEnum.FiveAndQuarter: + ataOneValue.Add("Device nominal size is 5.25\""); + + break; + case Identify.DeviceFormFactorEnum.ThreeAndHalf: + ataOneValue.Add("Device nominal size is 3.5\""); + + break; + case Identify.DeviceFormFactorEnum.TwoAndHalf: + ataOneValue.Add("Device nominal size is 2.5\""); + + break; + case Identify.DeviceFormFactorEnum.OnePointEight: + ataOneValue.Add("Device nominal size is 1.8\""); + + break; + case Identify.DeviceFormFactorEnum.LessThanOnePointEight: + ataOneValue.Add("Device nominal size is smaller than 1.8\""); + + break; + default: + ataOneValue.Add($"Device nominal size field value {ataIdentify.DeviceFormFactor} is unknown"); + + break; + } + } + + if(atapi) + { + if(ataIdentify.ATAPIByteCount > 0) + ataOneValue.Add($"{ataIdentify.ATAPIByteCount} bytes count limit for ATAPI"); + } + + if(cfa) + { + if((ataIdentify.CFAPowerMode & 0x8000) == 0x8000) + { + ataOneValue.Add("CompactFlash device supports power mode 1"); + + if((ataIdentify.CFAPowerMode & 0x2000) == 0x2000) + ataOneValue.Add("CompactFlash power mode 1 required for one or more commands"); + + if((ataIdentify.CFAPowerMode & 0x1000) == 0x1000) + ataOneValue.Add("CompactFlash power mode 1 is disabled"); + + ataOneValue.Add($"CompactFlash device uses a maximum of {ataIdentify.CFAPowerMode & 0x0FFF} mA"); + } + } + + ataOneValue.Add("Command set and features:"); + + if(ataIdentify.CommandSet.HasFlag(Identify.CommandSetBit.Nop)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet.HasFlag(Identify.CommandSetBit.Nop) + ? "NOP is supported and enabled" + : "NOP is supported"); + } + + if(ataIdentify.CommandSet.HasFlag(Identify.CommandSetBit.ReadBuffer)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet.HasFlag(Identify.CommandSetBit.ReadBuffer) + ? "READ BUFFER is supported and enabled" + : "READ BUFFER is supported"); + } + + if(ataIdentify.CommandSet.HasFlag(Identify.CommandSetBit.WriteBuffer)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet.HasFlag(Identify.CommandSetBit.WriteBuffer) + ? "WRITE BUFFER is supported and enabled" + : "WRITE BUFFER is supported"); + } + + if(ataIdentify.CommandSet.HasFlag(Identify.CommandSetBit.HPA)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet.HasFlag(Identify.CommandSetBit.HPA) + ? "Host Protected Area is supported and enabled" + : "Host Protected Area is supported"); + } + + if(ataIdentify.CommandSet.HasFlag(Identify.CommandSetBit.DeviceReset)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet.HasFlag(Identify.CommandSetBit.DeviceReset) + ? "DEVICE RESET is supported and enabled" + : "DEVICE RESET is supported"); + } + + if(ataIdentify.CommandSet.HasFlag(Identify.CommandSetBit.Service)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet.HasFlag(Identify.CommandSetBit.Service) + ? "SERVICE interrupt is supported and enabled" + : "SERVICE interrupt is supported"); + } + + if(ataIdentify.CommandSet.HasFlag(Identify.CommandSetBit.Release)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet.HasFlag(Identify.CommandSetBit.Release) + ? "Release is supported and enabled" + : "Release is supported"); + } + + if(ataIdentify.CommandSet.HasFlag(Identify.CommandSetBit.LookAhead)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet.HasFlag(Identify.CommandSetBit.LookAhead) + ? "Look-ahead read is supported and enabled" + : "Look-ahead read is supported"); + } + + if(ataIdentify.CommandSet.HasFlag(Identify.CommandSetBit.WriteCache)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet.HasFlag(Identify.CommandSetBit.WriteCache) + ? "Write cache is supported and enabled" + : "Write cache is supported"); + } + + if(ataIdentify.CommandSet.HasFlag(Identify.CommandSetBit.Packet)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet.HasFlag(Identify.CommandSetBit.Packet) + ? "PACKET is supported and enabled" + : "PACKET is supported"); + } + + if(ataIdentify.CommandSet.HasFlag(Identify.CommandSetBit.PowerManagement)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet.HasFlag(Identify.CommandSetBit.PowerManagement) + ? "Power management is supported and enabled" + : "Power management is supported"); + } + + if(ataIdentify.CommandSet.HasFlag(Identify.CommandSetBit.RemovableMedia)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet.HasFlag(Identify.CommandSetBit.RemovableMedia) + ? "Removable media feature set is supported and enabled" + : "Removable media feature set is supported"); + } + + if(ataIdentify.CommandSet.HasFlag(Identify.CommandSetBit.SecurityMode)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet.HasFlag(Identify.CommandSetBit.SecurityMode) + ? "Security mode is supported and enabled" + : "Security mode is supported"); + } + + if(ataIdentify.Capabilities.HasFlag(Identify.CapabilitiesBit.LBASupport)) + ataOneValue.Add("28-bit LBA is supported"); + + if(ataIdentify.CommandSet2.HasFlag(Identify.CommandSetBit2.MustBeSet) && + !ataIdentify.CommandSet2.HasFlag(Identify.CommandSetBit2.MustBeClear)) + { + if(ataIdentify.CommandSet2.HasFlag(Identify.CommandSetBit2.LBA48)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet2.HasFlag(Identify.CommandSetBit2.LBA48) + ? "48-bit LBA is supported and enabled" + : "48-bit LBA is supported"); + } + + if(ataIdentify.CommandSet2.HasFlag(Identify.CommandSetBit2.FlushCache)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet2.HasFlag(Identify.CommandSetBit2.FlushCache) + ? "FLUSH CACHE is supported and enabled" + : "FLUSH CACHE is supported"); + } + + if(ataIdentify.CommandSet2.HasFlag(Identify.CommandSetBit2.FlushCacheExt)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet2.HasFlag(Identify.CommandSetBit2.FlushCacheExt) + ? "FLUSH CACHE EXT is supported and enabled" + : "FLUSH CACHE EXT is supported"); + } + + if(ataIdentify.CommandSet2.HasFlag(Identify.CommandSetBit2.DCO)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet2.HasFlag(Identify.CommandSetBit2.DCO) + ? "Device Configuration Overlay feature set is supported and enabled" + : "Device Configuration Overlay feature set is supported"); + } + + if(ataIdentify.CommandSet2.HasFlag(Identify.CommandSetBit2.AAM)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet2.HasFlag(Identify.CommandSetBit2.AAM) + ? $"Automatic Acoustic Management is supported and enabled with value {ataIdentify.CurrentAAM} (vendor recommends {ataIdentify.RecommendedAAM}" + : "Automatic Acoustic Management is supported"); + } + + if(ataIdentify.CommandSet2.HasFlag(Identify.CommandSetBit2.SetMax)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet2.HasFlag(Identify.CommandSetBit2.SetMax) + ? "SET MAX security extension is supported and enabled" + : "SET MAX security extension is supported"); + } + + if(ataIdentify.CommandSet2.HasFlag(Identify.CommandSetBit2.AddressOffsetReservedAreaBoot)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet2.HasFlag(Identify.CommandSetBit2 + .AddressOffsetReservedAreaBoot) + ? "Address Offset Reserved Area Boot is supported and enabled" + : "Address Offset Reserved Area Boot is supported"); + } + + if(ataIdentify.CommandSet2.HasFlag(Identify.CommandSetBit2.SetFeaturesRequired)) + ataOneValue.Add("SET FEATURES is required before spin-up"); + + if(ataIdentify.CommandSet2.HasFlag(Identify.CommandSetBit2.PowerUpInStandby)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet2.HasFlag(Identify.CommandSetBit2.PowerUpInStandby) + ? "Power-up in standby is supported and enabled" + : "Power-up in standby is supported"); + } + + if(ataIdentify.CommandSet2.HasFlag(Identify.CommandSetBit2.RemovableNotification)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet2.HasFlag(Identify.CommandSetBit2.RemovableNotification) + ? "Removable Media Status Notification is supported and enabled" + : "Removable Media Status Notification is supported"); + } + + if(ataIdentify.CommandSet2.HasFlag(Identify.CommandSetBit2.APM)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet2.HasFlag(Identify.CommandSetBit2.APM) + ? $"Advanced Power Management is supported and enabled with value {ataIdentify.CurrentAPM}" + : "Advanced Power Management is supported"); + } + + if(ataIdentify.CommandSet2.HasFlag(Identify.CommandSetBit2.CompactFlash)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet2.HasFlag(Identify.CommandSetBit2.CompactFlash) + ? "CompactFlash feature set is supported and enabled" + : "CompactFlash feature set is supported"); + } + + if(ataIdentify.CommandSet2.HasFlag(Identify.CommandSetBit2.RWQueuedDMA)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet2.HasFlag(Identify.CommandSetBit2.RWQueuedDMA) + ? "READ DMA QUEUED and WRITE DMA QUEUED are supported and enabled" + : "READ DMA QUEUED and WRITE DMA QUEUED are supported"); + } + + if(ataIdentify.CommandSet2.HasFlag(Identify.CommandSetBit2.DownloadMicrocode)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet2.HasFlag(Identify.CommandSetBit2.DownloadMicrocode) + ? "DOWNLOAD MICROCODE is supported and enabled" + : "DOWNLOAD MICROCODE is supported"); + } + } + + if(ataIdentify.CommandSet.HasFlag(Identify.CommandSetBit.SMART)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet.HasFlag(Identify.CommandSetBit.SMART) + ? "S.M.A.R.T. is supported and enabled" + : "S.M.A.R.T. is supported"); + } + + if(ataIdentify.SCTCommandTransport.HasFlag(Identify.SCTCommandTransportBit.Supported)) + ataOneValue.Add("S.M.A.R.T. Command Transport is supported"); + + if(ataIdentify.CommandSet3.HasFlag(Identify.CommandSetBit3.MustBeSet) && + !ataIdentify.CommandSet3.HasFlag(Identify.CommandSetBit3.MustBeClear)) + { + if(ataIdentify.CommandSet3.HasFlag(Identify.CommandSetBit3.SMARTSelfTest)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet3.HasFlag(Identify.CommandSetBit3.SMARTSelfTest) + ? "S.M.A.R.T. self-testing is supported and enabled" + : "S.M.A.R.T. self-testing is supported"); + } + + if(ataIdentify.CommandSet3.HasFlag(Identify.CommandSetBit3.SMARTLog)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet3.HasFlag(Identify.CommandSetBit3.SMARTLog) + ? "S.M.A.R.T. error logging is supported and enabled" + : "S.M.A.R.T. error logging is supported"); + } + + if(ataIdentify.CommandSet3.HasFlag(Identify.CommandSetBit3.IdleImmediate)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet3.HasFlag(Identify.CommandSetBit3.IdleImmediate) + ? "IDLE IMMEDIATE with UNLOAD FEATURE is supported and enabled" + : "IDLE IMMEDIATE with UNLOAD FEATURE is supported"); + } + + if(ataIdentify.CommandSet3.HasFlag(Identify.CommandSetBit3.WriteURG)) + ataOneValue.Add("URG bit is supported in WRITE STREAM DMA EXT and WRITE STREAM EXT"); + + if(ataIdentify.CommandSet3.HasFlag(Identify.CommandSetBit3.ReadURG)) + ataOneValue.Add("URG bit is supported in READ STREAM DMA EXT and READ STREAM EXT"); + + if(ataIdentify.CommandSet3.HasFlag(Identify.CommandSetBit3.WWN)) + ataOneValue.Add("Device has a World Wide Name"); + + if(ataIdentify.CommandSet3.HasFlag(Identify.CommandSetBit3.FUAWriteQ)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet3.HasFlag(Identify.CommandSetBit3.FUAWriteQ) + ? "WRITE DMA QUEUED FUA EXT is supported and enabled" + : "WRITE DMA QUEUED FUA EXT is supported"); + } + + if(ataIdentify.CommandSet3.HasFlag(Identify.CommandSetBit3.FUAWrite)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet3.HasFlag(Identify.CommandSetBit3.FUAWrite) + ? "WRITE DMA FUA EXT and WRITE MULTIPLE FUA EXT are supported and enabled" + : "WRITE DMA FUA EXT and WRITE MULTIPLE FUA EXT are supported"); + } + + if(ataIdentify.CommandSet3.HasFlag(Identify.CommandSetBit3.GPL)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet3.HasFlag(Identify.CommandSetBit3.GPL) + ? "General Purpose Logging is supported and enabled" + : "General Purpose Logging is supported"); + } + + if(ataIdentify.CommandSet3.HasFlag(Identify.CommandSetBit3.Streaming)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet3.HasFlag(Identify.CommandSetBit3.Streaming) + ? "Streaming feature set is supported and enabled" + : "Streaming feature set is supported"); + } + + if(ataIdentify.CommandSet3.HasFlag(Identify.CommandSetBit3.MCPT)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet3.HasFlag(Identify.CommandSetBit3.MCPT) + ? "Media Card Pass Through command set is supported and enabled" + : "Media Card Pass Through command set is supported"); + } + + if(ataIdentify.CommandSet3.HasFlag(Identify.CommandSetBit3.MediaSerial)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet3.HasFlag(Identify.CommandSetBit3.MediaSerial) + ? "Media Serial is supported and valid" + : "Media Serial is supported"); + } + } + + if(ataIdentify.CommandSet4.HasFlag(Identify.CommandSetBit4.MustBeSet) && + !ataIdentify.CommandSet4.HasFlag(Identify.CommandSetBit4.MustBeClear)) + { + if(ataIdentify.CommandSet4.HasFlag(Identify.CommandSetBit4.DSN)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet4.HasFlag(Identify.CommandSetBit4.DSN) + ? "DSN feature set is supported and enabled" + : "DSN feature set is supported"); + } + + if(ataIdentify.CommandSet4.HasFlag(Identify.CommandSetBit4.AMAC)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet4.HasFlag(Identify.CommandSetBit4.AMAC) + ? "Accessible Max Address Configuration is supported and enabled" + : "Accessible Max Address Configuration is supported"); + } + + if(ataIdentify.CommandSet4.HasFlag(Identify.CommandSetBit4.ExtPowerCond)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet4.HasFlag(Identify.CommandSetBit4.ExtPowerCond) + ? "Extended Power Conditions are supported and enabled" + : "Extended Power Conditions are supported"); + } + + if(ataIdentify.CommandSet4.HasFlag(Identify.CommandSetBit4.ExtStatusReport)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet4.HasFlag(Identify.CommandSetBit4.ExtStatusReport) + ? "Extended Status Reporting is supported and enabled" + : "Extended Status Reporting is supported"); + } + + if(ataIdentify.CommandSet4.HasFlag(Identify.CommandSetBit4.FreeFallControl)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet4.HasFlag(Identify.CommandSetBit4.FreeFallControl) + ? "Free-fall control feature set is supported and enabled" + : "Free-fall control feature set is supported"); + } + + if(ataIdentify.CommandSet4.HasFlag(Identify.CommandSetBit4.SegmentedDownloadMicrocode)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet4.HasFlag(Identify.CommandSetBit4 + .SegmentedDownloadMicrocode) + ? "Segmented feature in DOWNLOAD MICROCODE is supported and enabled" + : "Segmented feature in DOWNLOAD MICROCODE is supported"); + } + + if(ataIdentify.CommandSet4.HasFlag(Identify.CommandSetBit4.RWDMAExtGpl)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet4.HasFlag(Identify.CommandSetBit4.RWDMAExtGpl) + ? "READ/WRITE DMA EXT GPL are supported and enabled" + : "READ/WRITE DMA EXT GPL are supported"); + } + + if(ataIdentify.CommandSet4.HasFlag(Identify.CommandSetBit4.WriteUnc)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet4.HasFlag(Identify.CommandSetBit4.WriteUnc) + ? "WRITE UNCORRECTABLE is supported and enabled" + : "WRITE UNCORRECTABLE is supported"); + } + + if(ataIdentify.CommandSet4.HasFlag(Identify.CommandSetBit4.WRV)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet4.HasFlag(Identify.CommandSetBit4.WRV) + ? "Write/Read/Verify is supported and enabled" + : "Write/Read/Verify is supported"); + + ataOneValue.Add($"{ataIdentify.WRVSectorCountMode2} sectors for Write/Read/Verify mode 2"); + ataOneValue.Add($"{ataIdentify.WRVSectorCountMode3} sectors for Write/Read/Verify mode 3"); + + if(ataIdentify.EnabledCommandSet4.HasFlag(Identify.CommandSetBit4.WRV)) + ataOneValue.Add($"Current Write/Read/Verify mode: {ataIdentify.WRVMode}"); + } + + if(ataIdentify.CommandSet4.HasFlag(Identify.CommandSetBit4.DT1825)) + { + ataOneValue.Add(ataIdentify.EnabledCommandSet4.HasFlag(Identify.CommandSetBit4.DT1825) + ? "DT1825 is supported and enabled" + : "DT1825 is supported"); + } + } + + if(true) + { + if(ataIdentify.Capabilities3.HasFlag(Identify.CapabilitiesBit3.BlockErase)) + ataOneValue.Add("BLOCK ERASE EXT is supported"); + + if(ataIdentify.Capabilities3.HasFlag(Identify.CapabilitiesBit3.Overwrite)) + ataOneValue.Add("OVERWRITE EXT is supported"); + + if(ataIdentify.Capabilities3.HasFlag(Identify.CapabilitiesBit3.CryptoScramble)) + ataOneValue.Add("CRYPTO SCRAMBLE EXT is supported"); + } + + if(true) + { + if(ataIdentify.CommandSet5.HasFlag(Identify.CommandSetBit5.DeviceConfDMA)) + ataOneValue.Add("DEVICE CONFIGURATION IDENTIFY DMA and DEVICE CONFIGURATION SET DMA are supported"); + + if(ataIdentify.CommandSet5.HasFlag(Identify.CommandSetBit5.ReadBufferDMA)) + ataOneValue.Add("READ BUFFER DMA is supported"); + + if(ataIdentify.CommandSet5.HasFlag(Identify.CommandSetBit5.WriteBufferDMA)) + ataOneValue.Add("WRITE BUFFER DMA is supported"); + + if(ataIdentify.CommandSet5.HasFlag(Identify.CommandSetBit5.DownloadMicroCodeDMA)) + ataOneValue.Add("DOWNLOAD MICROCODE DMA is supported"); + + if(ataIdentify.CommandSet5.HasFlag(Identify.CommandSetBit5.SetMaxDMA)) + ataOneValue.Add("SET PASSWORD DMA and SET UNLOCK DMA are supported"); + + if(ataIdentify.CommandSet5.HasFlag(Identify.CommandSetBit5.Ata28)) + ataOneValue.Add("Not all 28-bit commands are supported"); + + if(ataIdentify.CommandSet5.HasFlag(Identify.CommandSetBit5.CFast)) + ataOneValue.Add("Device follows CFast specification"); + + if(ataIdentify.CommandSet5.HasFlag(Identify.CommandSetBit5.IEEE1667)) + ataOneValue.Add("Device follows IEEE-1667"); + + if(ataIdentify.CommandSet5.HasFlag(Identify.CommandSetBit5.DeterministicTrim)) + { + ataOneValue.Add("Read after TRIM is deterministic"); + + if(ataIdentify.CommandSet5.HasFlag(Identify.CommandSetBit5.ReadZeroTrim)) + ataOneValue.Add("Read after TRIM returns empty data"); + } + + if(ataIdentify.CommandSet5.HasFlag(Identify.CommandSetBit5.LongPhysSectorAligError)) + ataOneValue.Add("Device supports Long Physical Sector Alignment Error Reporting Control"); + + if(ataIdentify.CommandSet5.HasFlag(Identify.CommandSetBit5.Encrypted)) + ataOneValue.Add("Device encrypts all user data"); + + if(ataIdentify.CommandSet5.HasFlag(Identify.CommandSetBit5.AllCacheNV)) + ataOneValue.Add("Device's write cache is non-volatile"); + + if(ataIdentify.CommandSet5.HasFlag(Identify.CommandSetBit5.ZonedBit0) || + ataIdentify.CommandSet5.HasFlag(Identify.CommandSetBit5.ZonedBit1)) + ataOneValue.Add("Device is zoned"); + } + + if(true) + { + if(ataIdentify.Capabilities3.HasFlag(Identify.CapabilitiesBit3.Sanitize)) + { + ataOneValue.Add("Sanitize feature set is supported"); + + ataOneValue.Add(ataIdentify.Capabilities3.HasFlag(Identify.CapabilitiesBit3.SanitizeCommands) + ? "Sanitize commands are specified by ACS-3 or higher" + : "Sanitize commands are specified by ACS-2"); + + if(ataIdentify.Capabilities3.HasFlag(Identify.CapabilitiesBit3.SanitizeAntifreeze)) + ataOneValue.Add("SANITIZE ANTIFREEZE LOCK EXT is supported"); + } + } + + if(!ata1 && maxAtaLevel >= 8) + { + if(ataIdentify.TrustedComputing.HasFlag(Identify.TrustedComputingBit.Set) && + !ataIdentify.TrustedComputing.HasFlag(Identify.TrustedComputingBit.Clear) && + ataIdentify.TrustedComputing.HasFlag(Identify.TrustedComputingBit.TrustedComputing)) + ataOneValue.Add("Trusted Computing feature set is supported"); + } + + if((ataIdentify.TransportMajorVersion & 0xF000) >> 12 == 0x1 || + (ataIdentify.TransportMajorVersion & 0xF000) >> 12 == 0xE) + { + if(true) + { + if(!ataIdentify.SATACapabilities.HasFlag(Identify.SATACapabilitiesBit.Clear)) + { + if(ataIdentify.SATACapabilities.HasFlag(Identify.SATACapabilitiesBit.ReadLogDMAExt)) + ataOneValue.Add("READ LOG DMA EXT is supported"); + } + } + + if(true) + { + if(!ataIdentify.SATACapabilities2.HasFlag(Identify.SATACapabilitiesBit2.Clear)) + { + if(ataIdentify.SATACapabilities2.HasFlag(Identify.SATACapabilitiesBit2.FPDMAQ)) + ataOneValue.Add("RECEIVE FPDMA QUEUED and SEND FPDMA QUEUED are supported"); + } + } + + if(true) + { + if(!ataIdentify.SATAFeatures.HasFlag(Identify.SATAFeaturesBit.Clear)) + { + if(ataIdentify.SATAFeatures.HasFlag(Identify.SATAFeaturesBit.NonZeroBufferOffset)) + { + ataOneValue.Add(ataIdentify.EnabledSATAFeatures.HasFlag(Identify.SATAFeaturesBit + .NonZeroBufferOffset) + ? "Non-zero buffer offsets are supported and enabled" + : "Non-zero buffer offsets are supported"); + } + + if(ataIdentify.SATAFeatures.HasFlag(Identify.SATAFeaturesBit.DMASetup)) + { + ataOneValue.Add(ataIdentify.EnabledSATAFeatures.HasFlag(Identify.SATAFeaturesBit.DMASetup) + ? "DMA Setup auto-activation is supported and enabled" + : "DMA Setup auto-activation is supported"); + } + + if(ataIdentify.SATAFeatures.HasFlag(Identify.SATAFeaturesBit.InitPowerMgmt)) + { + ataOneValue.Add(ataIdentify.EnabledSATAFeatures.HasFlag(Identify.SATAFeaturesBit.InitPowerMgmt) + ? "Device-initiated power management is supported and enabled" + : "Device-initiated power management is supported"); + } + + if(ataIdentify.SATAFeatures.HasFlag(Identify.SATAFeaturesBit.InOrderData)) + { + ataOneValue.Add(ataIdentify.EnabledSATAFeatures.HasFlag(Identify.SATAFeaturesBit.InOrderData) + ? "In-order data delivery is supported and enabled" + : "In-order data delivery is supported"); + } + + switch(atapi) + { + case false: + { + if(ataIdentify.SATAFeatures.HasFlag(Identify.SATAFeaturesBit.HardwareFeatureControl)) + { + ataOneValue.Add(ataIdentify.EnabledSATAFeatures.HasFlag(Identify.SATAFeaturesBit + .HardwareFeatureControl) + ? "Hardware Feature Control is supported and enabled" + : "Hardware Feature Control is supported"); + } + + break; + } + case true: + { + if(ataIdentify.SATAFeatures.HasFlag(Identify.SATAFeaturesBit.AsyncNotification)) + { + if(ataIdentify.EnabledSATAFeatures.HasFlag(Identify.SATAFeaturesBit.AsyncNotification)) + ataOneValue.Add("Asynchronous notification is supported"); + else + ataOneValue.Add("Asynchronous notification is supported"); + } + + break; + } + } + + if(ataIdentify.SATAFeatures.HasFlag(Identify.SATAFeaturesBit.SettingsPreserve)) + { + if(ataIdentify.EnabledSATAFeatures.HasFlag(Identify.SATAFeaturesBit.SettingsPreserve)) + ataOneValue.Add("Software Settings Preservation is supported"); + else + ataOneValue.Add("Software Settings Preservation is supported"); + } + + if(ataIdentify.SATAFeatures.HasFlag(Identify.SATAFeaturesBit.NCQAutoSense)) + ataOneValue.Add("NCQ Autosense is supported"); + + if(ataIdentify.EnabledSATAFeatures.HasFlag(Identify.SATAFeaturesBit.EnabledSlumber)) + ataOneValue.Add("Automatic Partial to Slumber transitions are enabled"); + } + } + } + + if((ataIdentify.RemovableStatusSet & 0x03) > 0) + ataOneValue.Add("Removable Media Status Notification feature set is supported"); + + if(ataIdentify.FreeFallSensitivity != 0x00 && ataIdentify.FreeFallSensitivity != 0xFF) + ataOneValue.Add($"Free-fall sensitivity set to {ataIdentify.FreeFallSensitivity}"); + + if(ataIdentify.DataSetMgmt.HasFlag(Identify.DataSetMgmtBit.Trim)) ataOneValue.Add("TRIM is supported"); + + if(ataIdentify.DataSetMgmtSize > 0) + ataOneValue.Add($"DATA SET MANAGEMENT can receive a maximum of {ataIdentify.DataSetMgmtSize} blocks of 512 bytes"); + + if(ataIdentify.SecurityStatus.HasFlag(Identify.SecurityStatusBit.Supported)) + { + ataOneValue.Add("Security:"); + + if(ataIdentify.SecurityStatus.HasFlag(Identify.SecurityStatusBit.Enabled)) + { + ataOneValue.Add("Security is enabled"); + + ataOneValue.Add(ataIdentify.SecurityStatus.HasFlag(Identify.SecurityStatusBit.Locked) + ? "Security is locked" + : "Security is not locked"); + + ataOneValue.Add(ataIdentify.SecurityStatus.HasFlag(Identify.SecurityStatusBit.Frozen) + ? "Security is frozen" + : "Security is not frozen"); + + ataOneValue.Add(ataIdentify.SecurityStatus.HasFlag(Identify.SecurityStatusBit.Expired) + ? "Security count has expired" + : "Security count has not expired"); + + ataOneValue.Add(ataIdentify.SecurityStatus.HasFlag(Identify.SecurityStatusBit.Maximum) + ? "Security level is maximum" + : "Security level is high"); + } + else + ataOneValue.Add("Security is not enabled"); + + if(ataIdentify.SecurityStatus.HasFlag(Identify.SecurityStatusBit.Enhanced)) + ataOneValue.Add("Supports enhanced security erase"); + + ataOneValue.Add($"{ataIdentify.SecurityEraseTime * 2} minutes to complete secure erase"); + + if(ataIdentify.SecurityStatus.HasFlag(Identify.SecurityStatusBit.Enhanced)) + ataOneValue.Add($"{ataIdentify.EnhancedSecurityEraseTime * 2} minutes to complete enhanced secure erase"); + + ataOneValue.Add($"Master password revision code: {ataIdentify.MasterPasswordRevisionCode}"); + } + + if(ataIdentify.CommandSet3.HasFlag(Identify.CommandSetBit3.MustBeSet) && + !ataIdentify.CommandSet3.HasFlag(Identify.CommandSetBit3.MustBeClear) && + ataIdentify.CommandSet3.HasFlag(Identify.CommandSetBit3.Streaming)) + { + ataOneValue.Add("Streaming:"); + ataOneValue.Add($"Minimum request size is {ataIdentify.StreamMinReqSize}"); + ataOneValue.Add($"Streaming transfer time in PIO is {ataIdentify.StreamTransferTimePIO}"); + ataOneValue.Add($"Streaming transfer time in DMA is {ataIdentify.StreamTransferTimeDMA}"); + ataOneValue.Add($"Streaming access latency is {ataIdentify.StreamAccessLatency}"); + ataOneValue.Add($"Streaming performance granularity is {ataIdentify.StreamPerformanceGranularity}"); + } + + if(ataIdentify.SCTCommandTransport.HasFlag(Identify.SCTCommandTransportBit.Supported)) + { + ataOneValue.Add("S.M.A.R.T. Command Transport (SCT):"); + + if(ataIdentify.SCTCommandTransport.HasFlag(Identify.SCTCommandTransportBit.LongSectorAccess)) + ataOneValue.Add("SCT Long Sector Address is supported"); + + if(ataIdentify.SCTCommandTransport.HasFlag(Identify.SCTCommandTransportBit.WriteSame)) + ataOneValue.Add("SCT Write Same is supported"); + + if(ataIdentify.SCTCommandTransport.HasFlag(Identify.SCTCommandTransportBit.ErrorRecoveryControl)) + ataOneValue.Add("SCT Error Recovery Control is supported"); + + if(ataIdentify.SCTCommandTransport.HasFlag(Identify.SCTCommandTransportBit.FeaturesControl)) + ataOneValue.Add("SCT Features Control is supported"); + + if(ataIdentify.SCTCommandTransport.HasFlag(Identify.SCTCommandTransportBit.DataTables)) + ataOneValue.Add("SCT Data Tables are supported"); + } + + if((ataIdentify.NVCacheCaps & 0x0010) == 0x0010) + { + ataOneValue.Add("Non-Volatile Cache:"); + ataOneValue.Add($"Version {(ataIdentify.NVCacheCaps & 0xF000) >> 12}"); + + if((ataIdentify.NVCacheCaps & 0x0001) == 0x0001) + { + ataOneValue.Add((ataIdentify.NVCacheCaps & 0x0002) == 0x0002 + ? "Power mode feature set is supported and enabled" + : "Power mode feature set is supported"); + + ataOneValue.Add($"Version {(ataIdentify.NVCacheCaps & 0x0F00) >> 8}"); + } + + ataOneValue.Add($"Non-Volatile Cache is {ataIdentify.NVCacheSize * logicalSectorSize} bytes"); + } + + if(ataReport.ReadCapabilities != null) + { + removable = false; + ataOneValue.Add(""); + + if(ataReport.ReadCapabilities.NominalRotationRate != null && + ataReport.ReadCapabilities.NominalRotationRate != 0x0000 && + ataReport.ReadCapabilities.NominalRotationRate != 0xFFFF) + { + ataOneValue.Add(ataReport.ReadCapabilities.NominalRotationRate == 0x0001 + ? "Device does not rotate." + : $"Device rotates at {ataReport.ReadCapabilities.NominalRotationRate} rpm"); + } + + if(!atapi) + { + if(ataReport.ReadCapabilities.BlockSize != null) + { + ataTwoValue.Add("Logical sector size", $"{ataReport.ReadCapabilities.BlockSize} bytes"); + logicalSectorSize = ataReport.ReadCapabilities.BlockSize.Value; + } + + if(ataReport.ReadCapabilities.PhysicalBlockSize != null) + ataTwoValue.Add("Physical sector size", $"{ataReport.ReadCapabilities.PhysicalBlockSize} bytes"); + + if(ataReport.ReadCapabilities.LongBlockSize != null) + ataTwoValue.Add("READ LONG sector size", $"{ataReport.ReadCapabilities.LongBlockSize} bytes"); + + if(ataReport.ReadCapabilities.BlockSize != null && + ataReport.ReadCapabilities.PhysicalBlockSize != null && + ataReport.ReadCapabilities.BlockSize.Value != ataReport.ReadCapabilities.PhysicalBlockSize.Value && + (ataReport.ReadCapabilities.LogicalAlignment & 0x8000) == 0x0000 && + (ataReport.ReadCapabilities.LogicalAlignment & 0x4000) == 0x4000) + { + ataOneValue + .Add($"Logical sector starts at offset {ataReport.ReadCapabilities.LogicalAlignment & 0x3FFF} from physical sector"); + } + + if(ataReport.ReadCapabilities.CHS != null && ataReport.ReadCapabilities.CurrentCHS != null) + { + int currentSectors = ataReport.ReadCapabilities.CurrentCHS.Cylinders * + ataReport.ReadCapabilities.CurrentCHS.Heads * + ataReport.ReadCapabilities.CurrentCHS.Sectors; + + ataTwoValue.Add("Cylinders", + $"{ataReport.ReadCapabilities.CHS.Cylinders} max., {ataReport.ReadCapabilities.CurrentCHS.Cylinders} current"); + + ataTwoValue.Add("Heads", + $"{ataReport.ReadCapabilities.CHS.Heads} max., {ataReport.ReadCapabilities.CurrentCHS.Heads} current"); + + ataTwoValue.Add("Sectors per track", + $"{ataReport.ReadCapabilities.CHS.Sectors} max., {ataReport.ReadCapabilities.CurrentCHS.Sectors} current"); + + ataTwoValue.Add("Sectors addressable in CHS mode", + $"{ataReport.ReadCapabilities.CHS.Cylinders * ataReport.ReadCapabilities.CHS.Heads * ataReport.ReadCapabilities.CHS.Sectors} max., {currentSectors} current"); + + ataTwoValue.Add("Device size in CHS mode", + $"{(ulong)currentSectors * logicalSectorSize} bytes, {(ulong)currentSectors * logicalSectorSize / 1000 / 1000} Mb, {(double)((ulong)currentSectors * logicalSectorSize) / 1024 / 1024:F2} MiB"); + } + else if(ataReport.ReadCapabilities.CHS != null) + { + int currentSectors = ataReport.ReadCapabilities.CHS.Cylinders * + ataReport.ReadCapabilities.CHS.Heads * + ataReport.ReadCapabilities.CHS.Sectors; + + ataTwoValue.Add("Cylinders", $"{ataReport.ReadCapabilities.CHS.Cylinders}"); + ataTwoValue.Add("Heads", $"{ataReport.ReadCapabilities.CHS.Heads}"); + ataTwoValue.Add("Sectors per track", $"{ataReport.ReadCapabilities.CHS.Sectors}"); + ataTwoValue.Add("Sectors addressable in CHS mode", $"{currentSectors}"); + + ataTwoValue.Add("Device size in CHS mode", + $"{(ulong)currentSectors * logicalSectorSize} bytes, {(ulong)currentSectors * logicalSectorSize / 1000 / 1000} Mb, {(double)((ulong)currentSectors * logicalSectorSize) / 1024 / 1024:F2} MiB"); + } + + if(ataReport.ReadCapabilities.LBASectors != null) + { + ataTwoValue.Add("Sectors addressable in sectors in 28-bit LBA mode", + $"{ataReport.ReadCapabilities.LBASectors}"); + + switch((ulong)ataReport.ReadCapabilities.LBASectors * logicalSectorSize / 1024 / 1024) + { + case > 1000000: + ataTwoValue.Add("Device size in 28-bit LBA mode", + $"{(ulong)ataReport.ReadCapabilities.LBASectors * logicalSectorSize} bytes, {(ulong)ataReport.ReadCapabilities.LBASectors * logicalSectorSize / 1000 / 1000 / 1000 / 1000} Tb, {(double)((ulong)ataReport.ReadCapabilities.LBASectors * logicalSectorSize) / 1024 / 1024 / 1024 / 1024:F2} TiB"); + + break; + case > 1000: + ataTwoValue.Add("Device size in 28-bit LBA mode", + $"{(ulong)ataReport.ReadCapabilities.LBASectors * logicalSectorSize} bytes, {(ulong)ataReport.ReadCapabilities.LBASectors * logicalSectorSize / 1000 / 1000 / 1000} Gb, {(double)((ulong)ataReport.ReadCapabilities.LBASectors * logicalSectorSize) / 1024 / 1024 / 1024:F2} GiB"); + + break; + default: + ataTwoValue.Add("Device size in 28-bit LBA mode", + $"{(ulong)ataReport.ReadCapabilities.LBASectors * logicalSectorSize} bytes, {(ulong)ataReport.ReadCapabilities.LBASectors * logicalSectorSize / 1000 / 1000} Mb, {(double)((ulong)ataReport.ReadCapabilities.LBASectors * logicalSectorSize) / 1024 / 1024:F2} MiB"); + + break; + } + } + + if(ataReport.ReadCapabilities.LBA48Sectors != null) + { + ataTwoValue.Add("Sectors addressable in sectors in 48-bit LBA mode", + $"{ataReport.ReadCapabilities.LBA48Sectors}"); + + switch(ataReport.ReadCapabilities.LBA48Sectors * logicalSectorSize / 1024 / 1024) + { + case > 1000000: + ataTwoValue.Add("Device size in 48-bit LBA mode", + $"{ataReport.ReadCapabilities.LBA48Sectors * logicalSectorSize} bytes, {ataReport.ReadCapabilities.LBA48Sectors * logicalSectorSize / 1000 / 1000 / 1000 / 1000} Tb, {(double)(ataReport.ReadCapabilities.LBA48Sectors * logicalSectorSize) / 1024 / 1024 / 1024 / 1024:F2} TiB"); + + break; + case > 1000: + ataTwoValue.Add("Device size in 48-bit LBA mode", + $"{ataReport.ReadCapabilities.LBA48Sectors * logicalSectorSize} bytes, {ataReport.ReadCapabilities.LBA48Sectors * logicalSectorSize / 1000 / 1000 / 1000} Gb, {(double)(ataReport.ReadCapabilities.LBA48Sectors * logicalSectorSize) / 1024 / 1024 / 1024:F2} GiB"); + + break; + default: + ataTwoValue.Add("Device size in 48-bit LBA mode", + $"{ataReport.ReadCapabilities.LBA48Sectors * logicalSectorSize} bytes, {ataReport.ReadCapabilities.LBA48Sectors * logicalSectorSize / 1000 / 1000} Mb, {(double)(ataReport.ReadCapabilities.LBA48Sectors * logicalSectorSize) / 1024 / 1024:F2} MiB"); + + break; + } + } + + if(ata1 || cfa) + { + if(ataReport.ReadCapabilities.UnformattedBPT > 0) + ataTwoValue.Add("Bytes per unformatted track", $"{ataReport.ReadCapabilities.UnformattedBPT}"); + + if(ataReport.ReadCapabilities.UnformattedBPS > 0) + ataTwoValue.Add("Bytes per unformatted sector", $"{ataReport.ReadCapabilities.UnformattedBPS}"); + } + } + + if(ataReport.ReadCapabilities.SupportsReadSectors == true) + ataOneValue.Add("Device supports READ SECTOR(S) command in CHS mode"); + + if(ataReport.ReadCapabilities.SupportsReadRetry == true) + ataOneValue.Add("Device supports READ SECTOR(S) RETRY command in CHS mode"); + + if(ataReport.ReadCapabilities.SupportsReadDma == true) + ataOneValue.Add("Device supports READ DMA command in CHS mode"); + + if(ataReport.ReadCapabilities.SupportsReadDmaRetry == true) + ataOneValue.Add("Device supports READ DMA RETRY command in CHS mode"); + + if(ataReport.ReadCapabilities.SupportsReadLong == true) + ataOneValue.Add("Device supports READ LONG command in CHS mode"); + + if(ataReport.ReadCapabilities.SupportsReadLongRetry == true) + ataOneValue.Add("Device supports READ LONG RETRY command in CHS mode"); + + if(ataReport.ReadCapabilities.SupportsReadLba == true) + ataOneValue.Add("Device supports READ SECTOR(S) command in 28-bit LBA mode"); + + if(ataReport.ReadCapabilities.SupportsReadRetryLba == true) + ataOneValue.Add("Device supports READ SECTOR(S) RETRY command in 28-bit LBA mode"); + + if(ataReport.ReadCapabilities.SupportsReadDmaLba == true) + ataOneValue.Add("Device supports READ DMA command in 28-bit LBA mode"); + + if(ataReport.ReadCapabilities.SupportsReadDmaRetryLba == true) + ataOneValue.Add("Device supports READ DMA RETRY command in 28-bit LBA mode"); + + if(ataReport.ReadCapabilities.SupportsReadLongLba == true) + ataOneValue.Add("Device supports READ LONG command in 28-bit LBA mode"); + + if(ataReport.ReadCapabilities.SupportsReadLongRetryLba == true) + ataOneValue.Add("Device supports READ LONG RETRY command in 28-bit LBA mode"); + + if(ataReport.ReadCapabilities.SupportsReadLba48 == true) + ataOneValue.Add("Device supports READ SECTOR(S) command in 48-bit LBA mode"); + + if(ataReport.ReadCapabilities.SupportsReadDmaLba48 == true) + ataOneValue.Add("Device supports READ DMA command in 48-bit LBA mode"); + + if(ataReport.ReadCapabilities.SupportsSeek == true) + ataOneValue.Add("Device supports SEEK command in CHS mode"); + + if(ataReport.ReadCapabilities.SupportsSeekLba == true) + ataOneValue.Add("Device supports SEEK command in 28-bit LBA mode"); + } + else + testedMedia = ataReport.RemovableMedias; + } +} \ No newline at end of file