From d43b3f6ec349c7be1620c1812eaa1a92de640663 Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Thu, 9 May 2024 17:40:01 +0100 Subject: [PATCH] Add SCSI to device report view. --- .../Components/Pages/Report/View.razor | 321 ++- .../Components/Pages/Report/View.razor.cs | 301 ++- Aaru.Server.New/Core/ScsiEvpd.cs | 294 +++ Aaru.Server.New/Core/ScsiInquiry.cs | 2238 +++++++++++++++++ Aaru.Server.New/Core/ScsiMmcFeatures.cs | 450 ++++ Aaru.Server.New/Core/ScsiMmcMode.cs | 214 ++ Aaru.Server.New/Core/ScsiModeSense.cs | 980 ++++++++ 7 files changed, 4746 insertions(+), 52 deletions(-) create mode 100644 Aaru.Server.New/Core/ScsiEvpd.cs create mode 100644 Aaru.Server.New/Core/ScsiInquiry.cs create mode 100644 Aaru.Server.New/Core/ScsiMmcFeatures.cs create mode 100644 Aaru.Server.New/Core/ScsiMmcMode.cs create mode 100644 Aaru.Server.New/Core/ScsiModeSense.cs diff --git a/Aaru.Server.New/Components/Pages/Report/View.razor b/Aaru.Server.New/Components/Pages/Report/View.razor index 7ddc7234..5a2c92e6 100644 --- a/Aaru.Server.New/Components/Pages/Report/View.razor +++ b/Aaru.Server.New/Components/Pages/Report/View.razor @@ -1,4 +1,5 @@ @page "/Report/View/{Id:int}" +@using Aaru.CommonTypes.Metadata @using Aaru.Server.Database @using Blazorise @rendermode InteractiveServer @@ -520,23 +521,317 @@ @if(ReadCapabilitiesDictionary is not null && ReadCapabilitiesList is not null) { - - - @foreach(KeyValuePair kvp in ReadCapabilitiesDictionary) + + + Read capabilities + + + +
+ + @foreach(KeyValuePair kvp in ReadCapabilitiesDictionary) + { + + @kvp.Key + @kvp.Value + + } + +
+ + @foreach(string cap in ReadCapabilitiesList) { - - @kvp.Key - @kvp.Value - + @cap } - - - - @foreach(string cap in ReadCapabilitiesList) + + +
+} +@if(DeviceInquiry is not null) +{ + + + + Device inquiry + + + + + + @foreach(KeyValuePair kvp in DeviceInquiry) + { + + @kvp.Key + @kvp.Value + + } + +
+ @if(InquiryCapabilities is not null) { - @cap + + @foreach(string cap in InquiryCapabilities) + { + @cap + } + } - +
+
+} +@if(ModeSenseCapabilities is not null || ModeSensePages is not null) +{ + + + + MODE SENSE pages + + + + @if(ModeSenseCapabilities is not null) + { + + @foreach(string cap in ModeSenseCapabilities) + { + @cap + } + + } + @if(BlockDescriptors is not null) + { + + + + + + Block descriptors + + + + + @foreach(string descriptor in BlockDescriptors) + { + @descriptor + } + + + + + } + @if(ModeSensePages is not null) + { + foreach(KeyValuePair> kvp in ModeSensePages) + { + + + + + @kvp.Key + + + @if(kvp.Value.Count > 0) + { + + + @foreach(string cap in kvp.Value) + { + @cap + } + + + } + + + } + } + + +} +@if(EvpdPages?.Count > 0) +{ + + + + Extended Vital Product Data pages + + + + @foreach(KeyValuePair> kvp in EvpdPages) + { + + + + + @kvp.Key + + + @if(kvp.Value.Count > 0) + { + + + @foreach(string cap in kvp.Value) + { + @cap + } + + + } + + + } + + +} +@if(MmcModeList?.Count > 0) +{ + + + + CD-ROM capabilities + + + + + @foreach(string cap in MmcModeList) + { + @cap + } + + + +} +@if(MmcFeaturesList?.Count > 0) +{ + + + + MMC features + + + + + @foreach(string feature in MmcFeaturesList) + { + @feature + } + + + +} +@if(ScsiSscVisible) +{ + + + + SCSI Streaming device capabilities: + + + + + + + Block size granularity + @ScsiSscGranularity + + + Maximum block length + @ScsiSscMaxBlock bytes + + + Minimum block length + @ScsiSscMinBlock bytes + + +
+ @if(ScsiSscDensities?.Count > 0) + { + foreach(SupportedDensity density in ScsiSscDensities) + { + + + + + Information for supported density with primary code @($"{density.PrimaryCode:X2}h") and secondary code @($"{density.SecondaryCode:X2}h") + + + + + + + Drive can write this density + @density.Writable + + + Duplicate density + @density.Duplicate + + + Default density + @density.DefaultDensity + + + Name + @density.Name + + + Organization + @density.Organization + + + Description + @density.Description + + + Maximum capacity + @density.Capacity megabytes + + + Density has @density.BitsPerMm bits per mm, with @density.Tracks tracks in a @density.Width mm width tape + + +
+
+
+
+ } + } + @if(ScsiSscMedias?.Count > 0) + { + foreach(SscSupportedMedia media in ScsiSscMedias) + { + + + + + Information for supported media with type code @($"{media.MediumType:X2}h") + + + + + + + Media is @media.Length m long in a @media.Width mm width tape + + + Name + @media.Name + + + Organization + @media.Organization + + + Description + @media.Description + + +
+
+
+
+ } + } +
} diff --git a/Aaru.Server.New/Components/Pages/Report/View.razor.cs b/Aaru.Server.New/Components/Pages/Report/View.razor.cs index 28926a7e..00b70d26 100644 --- a/Aaru.Server.New/Components/Pages/Report/View.razor.cs +++ b/Aaru.Server.New/Components/Pages/Report/View.razor.cs @@ -1,9 +1,15 @@ using Aaru.CommonTypes.Metadata; +using Aaru.CommonTypes.Structs.Devices.SCSI; using Aaru.Decoders.PCMCIA; +using Aaru.Decoders.SCSI; +using Aaru.Helpers; using Aaru.Server.Database.Models; +using Aaru.Server.New.Core; using Microsoft.AspNetCore.Components; using Microsoft.EntityFrameworkCore; +using Ata = Aaru.CommonTypes.Metadata.Ata; using DbContext = Aaru.Server.Database.DbContext; +using Inquiry = Aaru.CommonTypes.Structs.Devices.SCSI.Inquiry; using Tuple = Aaru.Decoders.PCMCIA.Tuple; namespace Aaru.Server.New.Components.Pages.Report; @@ -17,37 +23,51 @@ public partial class View [CascadingParameter] HttpContext HttpContext { get; set; } = default!; [Parameter] - public int Id { get; set; } - public Item? UsbItem { get; set; } - public Item? FireWireItem { get; set; } - public Dictionary? PcmciaTuples { get; set; } - public PcmciaItem? PcmciaItem { get; set; } - public string? lblDeviceType { get; set; } - public string? AtaItem { get; set; } - public string? MaximumAtaRevision { get; set; } - public List? SupportedAtaVersions { get; set; } - public Dictionary? DeviceIdentification { get; set; } - public string? AtaTransport { get; set; } - public List? AtaTransportVersions { get; set; } - public List? GeneralConfiguration { get; set; } - public List? SpecificConfiguration { get; set; } - public List? DeviceCapabilities { get; set; } - public List? CommandSetAndFeatures { get; set; } - public List? PioTransferModes { get; set; } - public List? DmaTransferModes { get; set; } - public List? MDmaTransferModes { get; set; } - public List? UltraDmaTransferModes { get; set; } - public List? NvCache { get; set; } - public List? SmartCommandTransport { get; set; } - public List? Streaming { get; set; } - public List? Security { get; set; } - public Dictionary? ReadCapabilitiesDictionary { get; set; } - public List? ReadCapabilitiesList { get; set; } - public string? Ocr { get; set; } - public string? ExtendedCsd { get; set; } - public string? Csd { get; set; } - public string? Cid { get; set; } - public string? Scr { get; set; } + public int Id { get; set; } + public Item? UsbItem { get; set; } + public Item? FireWireItem { get; set; } + public Dictionary? PcmciaTuples { get; set; } + public PcmciaItem? PcmciaItem { get; set; } + public string? lblDeviceType { get; set; } + public string? AtaItem { get; set; } + public string? MaximumAtaRevision { get; set; } + public List? SupportedAtaVersions { get; set; } + public Dictionary? DeviceIdentification { get; set; } + public Dictionary? DeviceInquiry { get; set; } + public string? AtaTransport { get; set; } + public List? AtaTransportVersions { get; set; } + public List? GeneralConfiguration { get; set; } + public List? SpecificConfiguration { get; set; } + public List? DeviceCapabilities { get; set; } + public List? CommandSetAndFeatures { get; set; } + public List? PioTransferModes { get; set; } + public List? DmaTransferModes { get; set; } + public List? MDmaTransferModes { get; set; } + public List? UltraDmaTransferModes { get; set; } + public List? NvCache { get; set; } + public List? SmartCommandTransport { get; set; } + public List? Streaming { get; set; } + public List? Security { get; set; } + public Dictionary? ReadCapabilitiesDictionary { get; set; } + public List? ReadCapabilitiesList { get; set; } + public string? Ocr { get; set; } + public string? ExtendedCsd { get; set; } + public string? Csd { get; set; } + public string? Cid { get; set; } + public string? Scr { get; set; } + 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; } /// protected override async Task OnInitializedAsync() @@ -73,6 +93,25 @@ public partial class View .Include(static deviceReportV2 => deviceReportV2.ATA) .Include(static deviceReportV2 => deviceReportV2.MultiMediaCard) .Include(static deviceReportV2 => deviceReportV2.SecureDigital) + .Include(static deviceReportV2 => deviceReportV2.SCSI) + .ThenInclude(static scsi => scsi.ModeSense) + .ThenInclude(static scsiMode => scsiMode.BlockDescriptors) + .Include(static deviceReportV2 => deviceReportV2.SCSI) + .ThenInclude(static scsi => scsi.ModeSense) + .ThenInclude(static scsiMode => scsiMode.ModePages) + .Include(static deviceReportV2 => deviceReportV2.SCSI) + .ThenInclude(static scsi => scsi.EVPDPages) + .Include(static deviceReportV2 => deviceReportV2.SCSI) + .ThenInclude(static scsi => scsi.MultiMediaDevice) + .ThenInclude(static mmc => mmc.Features) + .Include(static deviceReportV2 => deviceReportV2.SCSI) + .ThenInclude(static scsi => scsi.SequentialDevice) + .ThenInclude(static ssc => ssc.SupportedDensities) + .Include(static deviceReportV2 => deviceReportV2.SCSI) + .ThenInclude(static scsi => scsi.SequentialDevice) + .ThenInclude(static ssc => ssc.SupportedMediaTypes) + .Include(static deviceReportV2 => deviceReportV2.SCSI) + .ThenInclude(static scsi => scsi.ReadCapabilities) .FirstOrDefaultAsync(d => d.Id == Id); if(report is null) @@ -330,26 +369,210 @@ public partial class View lblDeviceType = "SecureDigital"; if(report.SecureDigital.CID != null) - { Cid = Decoders.SecureDigital.Decoders.PrettifyCID(report.SecureDigital.CID).Replace("\n", "
"); - } if(report.SecureDigital.CSD != null) - { Csd = Decoders.SecureDigital.Decoders.PrettifyCSD(report.SecureDigital.CSD).Replace("\n", "
"); - } if(report.SecureDigital.SCR != null) - { Scr = Decoders.SecureDigital.Decoders.PrettifySCR(report.SecureDigital.SCR).Replace("\n", "
"); - } if(report.SecureDigital.OCR != null) - { Ocr = Decoders.SecureDigital.Decoders.PrettifyCSD(report.SecureDigital.OCR).Replace("\n", "
"); - } } + if(report.SCSI != null) + { + var vendorId = ""; + + if(report.SCSI.Inquiry != null) + { + Inquiry inq = report.SCSI.Inquiry.Value; + vendorId = StringHandlers.CToString(report.SCSI.Inquiry?.VendorIdentification); + DeviceInquiry = new Dictionary(); + + 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)); + } + + List inquiryCapabilities = ScsiInquiry.Report(report.SCSI.Inquiry); + if(inquiryCapabilities.Count > 0) InquiryCapabilities = inquiryCapabilities; + + if(report.SCSI.SupportsModeSense6) + { + ModeSenseCapabilities ??= []; + ModeSenseCapabilities.Add("Device supports MODE SENSE (6)"); + } + + if(report.SCSI.SupportsModeSense10) + { + ModeSenseCapabilities ??= []; + ModeSenseCapabilities.Add("Device supports MODE SENSE (10)"); + } + + if(report.SCSI.SupportsModeSubpages) + { + ModeSenseCapabilities ??= []; + ModeSenseCapabilities.Add("Device supports MODE SENSE subpages"); + } + + if(report.SCSI.ModeSense != null) + { + PeripheralDeviceTypes devType = PeripheralDeviceTypes.DirectAccess; + + if(report.SCSI.Inquiry != null) + devType = (PeripheralDeviceTypes)report.SCSI.Inquiry.Value.PeripheralDeviceType; + + ScsiModeSense.Report(report.SCSI.ModeSense, + vendorId, + devType, + out List? modeSenseCapabilities, + out List? blockDescriptors, + out Dictionary> modePages); + + if(modePages.Count > 0) ModeSensePages = modePages; + + if(modeSenseCapabilities is not null) + { + ModeSenseCapabilities ??= new List(); + ModeSenseCapabilities.AddRange(modeSenseCapabilities); + } + + if(blockDescriptors is not null) BlockDescriptors = blockDescriptors; + } + + if(report.SCSI.EVPDPages != null) + { + ScsiEvpd.Report(report.SCSI.EVPDPages, vendorId, out Dictionary> evpdPages); + + if(evpdPages.Count > 0) EvpdPages = evpdPages; + } + + if(report.SCSI.MultiMediaDevice is not null) + { + // testedMedia = report.SCSI.MultiMediaDevice.TestedMedia; + + if(report.SCSI.MultiMediaDevice.ModeSense2A != null) + { + ScsiMmcMode.Report(report.SCSI.MultiMediaDevice.ModeSense2A, out List mmcModeList); + + if(mmcModeList.Count > 0) MmcModeList = mmcModeList; + } + + if(report.SCSI.MultiMediaDevice.Features != null) + { + ScsiMmcFeatures.Report(report.SCSI.MultiMediaDevice.Features, out List mmcFeaturesList); + + if(mmcFeaturesList.Count > 0) MmcFeaturesList = mmcFeaturesList; + } + } + else if(report.SCSI.SequentialDevice != null) + { + ScsiSscVisible = true; + + ScsiSscGranularity = report.SCSI.SequentialDevice.BlockSizeGranularity?.ToString() ?? "Unspecified"; + + ScsiSscMaxBlock = report.SCSI.SequentialDevice.MaxBlockLength?.ToString() ?? "Unspecified"; + + ScsiSscMinBlock = report.SCSI.SequentialDevice.MinBlockLength?.ToString() ?? "Unspecified"; + + if(report.SCSI.SequentialDevice.SupportedDensities != null) + ScsiSscDensities = report.SCSI.SequentialDevice.SupportedDensities; + + 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(mediaOneValue.Count > 0) + { + sscMedia = true; + ViewBag.repTestedMedia = mediaOneValue; + } + }*/ + } + else if(report.SCSI.ReadCapabilities != null) + { + List readCapabilitiesList = []; + var readCapabilitiesDictionary = new Dictionary(); + + if(report.SCSI.ReadCapabilities.Blocks.HasValue && report.SCSI.ReadCapabilities.BlockSize.HasValue) + { + readCapabilitiesDictionary.Add("Device has", + $"{report.SCSI.ReadCapabilities.Blocks} blocks of {report.SCSI.ReadCapabilities.BlockSize} bytes each"); + + switch(report.SCSI.ReadCapabilities.Blocks * report.SCSI.ReadCapabilities.BlockSize / 1024 / 1024) + { + case > 1000000: + readCapabilitiesDictionary.Add("Device size", + $"{report.SCSI.ReadCapabilities.Blocks * report.SCSI.ReadCapabilities.BlockSize} bytes, {report.SCSI.ReadCapabilities.Blocks * report.SCSI.ReadCapabilities.BlockSize / 1000 / 1000 / 1000 / 1000} Tb, {(double)(report.SCSI.ReadCapabilities.Blocks * report.SCSI.ReadCapabilities.BlockSize) / 1024 / 1024 / 1024 / 1024:F2} TiB"); + + break; + case > 1000: + readCapabilitiesDictionary.Add("Device size", + $"{report.SCSI.ReadCapabilities.Blocks * report.SCSI.ReadCapabilities.BlockSize} bytes, {report.SCSI.ReadCapabilities.Blocks * report.SCSI.ReadCapabilities.BlockSize / 1000 / 1000 / 1000} Gb, {(double)(report.SCSI.ReadCapabilities.Blocks * report.SCSI.ReadCapabilities.BlockSize) / 1024 / 1024 / 1024:F2} GiB"); + + break; + default: + readCapabilitiesDictionary.Add("Device size", + $"{report.SCSI.ReadCapabilities.Blocks * report.SCSI.ReadCapabilities.BlockSize} bytes, {report.SCSI.ReadCapabilities.Blocks * report.SCSI.ReadCapabilities.BlockSize / 1000 / 1000} Mb, {(double)(report.SCSI.ReadCapabilities.Blocks * report.SCSI.ReadCapabilities.BlockSize) / 1024 / 1024:F2} MiB"); + + break; + } + } + + 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"); + + 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."); + + if(report.SCSI.ReadCapabilities.SupportsReadCapacity16 == true) + readCapabilitiesList.Add("Device supports READ CAPACITY (16) command."); + + if(report.SCSI.ReadCapabilities.SupportsRead6 == true) + readCapabilitiesList.Add("Device supports READ (6) command."); + + if(report.SCSI.ReadCapabilities.SupportsRead10 == true) + readCapabilitiesList.Add("Device supports READ (10) command."); + + if(report.SCSI.ReadCapabilities.SupportsRead12 == true) + readCapabilitiesList.Add("Device supports READ (12) command."); + + if(report.SCSI.ReadCapabilities.SupportsRead16 == true) + readCapabilitiesList.Add("Device supports READ (16) command."); + + if(report.SCSI.ReadCapabilities.SupportsReadLong == true) + readCapabilitiesList.Add("Device supports READ LONG (10) command."); + + if(report.SCSI.ReadCapabilities.SupportsReadLong16 == true) + readCapabilitiesList.Add("Device supports READ LONG (16) command."); + + if(readCapabilitiesList.Count > 0) ReadCapabilitiesList = readCapabilitiesList; + if(readCapabilitiesDictionary.Count > 0) ReadCapabilitiesDictionary = readCapabilitiesDictionary; + } + /* else + testedMedia = report.SCSI.RemovableMedias; + */ + } _initialized = true; diff --git a/Aaru.Server.New/Core/ScsiEvpd.cs b/Aaru.Server.New/Core/ScsiEvpd.cs new file mode 100644 index 00000000..08362794 --- /dev/null +++ b/Aaru.Server.New/Core/ScsiEvpd.cs @@ -0,0 +1,294 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : ScsiEvpd.cs +// Author(s) : Natalia Portillo +// +// Component : Aaru Server. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SCSI EVPDs 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.Decoders.SCSI; + +namespace Aaru.Server.New.Core; + +public static class ScsiEvpd +{ + /// + /// Takes the SCSI EVPD part of a device report and prints it as a list key=value pairs to be sequenced by ASP.NET + /// in the rendering + /// + /// EVPD pages + /// SCSI vendor string + /// List to put the key=value pairs on + public static void Report(IEnumerable pages, string vendor, + out Dictionary> evpdPages) + { + evpdPages = new Dictionary>(); + vendor = vendor.ToLowerInvariant(); + + foreach(ScsiPage evpd in pages) + { + string header = evpd.page switch + { + >= 0x01 and <= 0x7F => $"EVPD page {evpd.page:X2}h: ASCII information", + 0x81 => "EVPD page 81h: Implemented operating definitions", + 0x82 => "EVPD page 82h: ASCII implemented operating definition", + 0x83 => "EVPD page 83h: Device identification", + 0x84 => "EVPD page 84h: Software Interface Identifiers", + 0x85 => "EVPD page 85h: Management Network Addresses", + 0x86 => "EVPD page 86h: Extended INQUIRY Data", + 0x89 => "EVPD page 89h: SCSI to ATA Translation Layer Data", + 0xB0 => "EVPD page B0h: Sequential-access Device Capabilities", + 0xB2 => "EVPD page B2h: TapeAlert Supported Flags Bitmap", + 0xB4 => "EVPD page B4h: Unknown", + 0xC0 when vendor == "quantum" => + "EVPD page C0h: Quantum Firmware Build Information page", + 0xC0 when vendor == "seagate" => "EVPD page C0h: Seagate Firmware Numbers page", + 0xC0 when vendor == "ibm" => "EVPD page C0h: IBM Drive Component Revision Levels page", + 0xC1 when vendor == "ibm" => "EVPD page C1h: IBM Drive Serial Numbers page", + 0xC0 or 0xC1 when vendor == "certance" => + $"EVPD page {evpd.page:X2}h: Certance Drive Component Revision Levels page", + 0xC2 or 0xC3 or 0xC4 or 0xC5 or 0xC6 when vendor == "certance" => + $"EVPD page {evpd.page:X2}h: Certance Drive Component Serial Number page", + 0xC0 when vendor == "hp" => "EVPD page C0h: HP Drive Firmware Revision Levels page:", + 0xC1 when vendor == "hp" => "EVPD page C1h: HP Drive Hardware Revision Levels page", + 0xC2 when vendor == "hp" => "EVPD page C2h: HP Drive PCA Revision Levels page", + 0xC3 when vendor == "hp" => "EVPD page C3h: HP Drive Mechanism Revision Levels page", + 0xC4 when vendor == "hp" => + "EVPD page C4h: HP Drive Head Assembly Revision Levels page", + 0xC5 when vendor == "hp" => "EVPD page C5h: HP Drive ACI Revision Levels page", + 0xDF when vendor == "certance" => "EVPD page DFh: Certance drive status page", + _ => $"EVPD page {evpd.page:X2}h: Undecoded" + }; + + List decoded; + string? ascii; + + switch(evpd.page) + { + case >= 0x01 and <= 0x7F: + ascii = EVPD.DecodeASCIIPage(evpd.value); + + if(ascii is not null) + decoded = [ascii]; + else + decoded = []; + + break; + case 0x81: + ascii = EVPD.PrettifyPage_81(evpd.value); + + if(ascii is not null) + decoded = [ascii]; + else + decoded = []; + + break; + case 0x82: + ascii = EVPD.DecodePage82(evpd.value); + + if(ascii is not null) + decoded = [ascii]; + else + decoded = []; + + break; + case 0x83: + decoded = EVPD.PrettifyPage_83(evpd.value) + ?.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList() ?? []; + + break; + case 0x84: + decoded = EVPD.PrettifyPage_84(evpd.value) + ?.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList() ?? []; + + ; + + break; + case 0x85: + decoded = EVPD.PrettifyPage_85(evpd.value) + ?.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList() ?? []; + + ; + + break; + case 0x86: + decoded = EVPD.PrettifyPage_86(evpd.value) + ?.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList() ?? []; + + ; + + break; + case 0x89: + decoded = EVPD.PrettifyPage_89(evpd.value) + ?.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList() ?? []; + + ; + + break; + case 0xB0: + decoded = EVPD.PrettifyPage_B0(evpd.value) + ?.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList() ?? []; + + ; + + break; + case 0xB2: + decoded = [$"0x{EVPD.DecodePageB2(evpd.value):X16}"]; + + break; + case 0xB4: + ascii = EVPD.DecodePageB4(evpd.value); + + if(ascii is not null) + decoded = [ascii]; + else + decoded = []; + + break; + case 0xC0 when vendor == "quantum": + decoded = EVPD.PrettifyPage_C0_Quantum(evpd.value) + ?.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList() ?? []; + + ; + + break; + case 0xC0 when vendor == "seagate": + decoded = EVPD.PrettifyPage_C0_Seagate(evpd.value) + ?.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList() ?? []; + + ; + + break; + case 0xC0 when vendor == "ibm": + decoded = EVPD.PrettifyPage_C0_IBM(evpd.value) + ?.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList() ?? []; + + ; + + break; + case 0xC1 when vendor == "ibm": + decoded = EVPD.PrettifyPage_C1_IBM(evpd.value) + ?.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList() ?? []; + + ; + + break; + case 0xC0 or 0xC1 when vendor == "certance": + decoded = EVPD.PrettifyPage_C0_C1_Certance(evpd.value) + ?.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList() ?? []; + + ; + + break; + case 0xC2 or 0xC3 or 0xC4 or 0xC5 or 0xC6 when vendor == "certance": + decoded = EVPD.PrettifyPage_C2_C3_C4_C5_C6_Certance(evpd.value) + ?.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList() ?? []; + + ; + + break; + case 0xC0 or 0xC1 or 0xC2 or 0xC3 or 0xC4 or 0xC5 when vendor == "hp": + decoded = EVPD.PrettifyPage_C0_to_C5_HP(evpd.value) + ?.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList() ?? []; + + ; + + break; + case 0xDF when vendor == "certance": + decoded = EVPD.PrettifyPage_DF_Certance(evpd.value) + ?.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList() ?? []; + + ; + + break; + default: + decoded = []; + + break; + } + + evpdPages.Add(header, decoded); + } + } +} \ No newline at end of file diff --git a/Aaru.Server.New/Core/ScsiInquiry.cs b/Aaru.Server.New/Core/ScsiInquiry.cs new file mode 100644 index 00000000..0a16c4a3 --- /dev/null +++ b/Aaru.Server.New/Core/ScsiInquiry.cs @@ -0,0 +1,2238 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : ScsiInquiry.cs +// Author(s) : Natalia Portillo +// +// Component : Aaru Server. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SCSI INQUIRY 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.Structs.Devices.SCSI; + +namespace Aaru.Server.New.Core; + +static class ScsiInquiry +{ + /// + /// Takes the SCSI INQUIRY part of a device report and prints it as a list of values to be sequenced by ASP.NET in + /// the rendering + /// + /// INQUIRY part of the report + /// List of values + internal static List Report(Inquiry? inquiryNullable) + { + List scsiOneValue = new(); + + if(!inquiryNullable.HasValue) return scsiOneValue; + + Inquiry inquiry = inquiryNullable.Value; + + switch((PeripheralQualifiers)inquiry.PeripheralQualifier) + { + case PeripheralQualifiers.Supported: + scsiOneValue.Add("Device is connected and supported."); + + break; + case PeripheralQualifiers.Unconnected: + scsiOneValue.Add("Device is supported but not connected."); + + break; + case PeripheralQualifiers.Reserved: + scsiOneValue.Add("Reserved value set in Peripheral Qualifier field."); + + break; + case PeripheralQualifiers.Unsupported: + scsiOneValue.Add("Device is connected but unsupported."); + + break; + default: + scsiOneValue.Add($"Vendor value {inquiry.PeripheralQualifier} set in Peripheral Qualifier field."); + + break; + } + + switch((PeripheralDeviceTypes)inquiry.PeripheralDeviceType) + { + case PeripheralDeviceTypes.DirectAccess: //0x00, + scsiOneValue.Add("Direct-access device"); + + break; + case PeripheralDeviceTypes.SequentialAccess: //0x01, + scsiOneValue.Add("Sequential-access device"); + + break; + case PeripheralDeviceTypes.PrinterDevice: //0x02, + scsiOneValue.Add("Printer device"); + + break; + case PeripheralDeviceTypes.ProcessorDevice: //0x03, + scsiOneValue.Add("Processor device"); + + break; + case PeripheralDeviceTypes.WriteOnceDevice: //0x04, + scsiOneValue.Add("Write-once device"); + + break; + case PeripheralDeviceTypes.MultiMediaDevice: //0x05, + scsiOneValue.Add("CD-ROM/DVD/etc device"); + + break; + case PeripheralDeviceTypes.ScannerDevice: //0x06, + scsiOneValue.Add("Scanner device"); + + break; + case PeripheralDeviceTypes.OpticalDevice: //0x07, + scsiOneValue.Add("Optical memory device"); + + break; + case PeripheralDeviceTypes.MediumChangerDevice: //0x08, + scsiOneValue.Add("Medium change device"); + + break; + case PeripheralDeviceTypes.CommsDevice: //0x09, + scsiOneValue.Add("Communications device"); + + break; + case PeripheralDeviceTypes.PrePressDevice1: //0x0A, + scsiOneValue.Add("Graphics arts pre-press device (defined in ASC IT8)"); + + break; + case PeripheralDeviceTypes.PrePressDevice2: //0x0B, + scsiOneValue.Add("Graphics arts pre-press device (defined in ASC IT8)"); + + break; + case PeripheralDeviceTypes.ArrayControllerDevice: //0x0C, + scsiOneValue.Add("Array controller device"); + + break; + case PeripheralDeviceTypes.EnclosureServiceDevice: //0x0D, + scsiOneValue.Add("Enclosure services device"); + + break; + case PeripheralDeviceTypes.SimplifiedDevice: //0x0E, + scsiOneValue.Add("Simplified direct-access device"); + + break; + case PeripheralDeviceTypes.OCRWDevice: //0x0F, + scsiOneValue.Add("Optical card reader/writer device"); + + break; + case PeripheralDeviceTypes.BridgingExpander: //0x10, + scsiOneValue.Add("Bridging Expanders"); + + break; + case PeripheralDeviceTypes.ObjectDevice: //0x11, + scsiOneValue.Add("Object-based Storage Device"); + + break; + case PeripheralDeviceTypes.ADCDevice: //0x12, + scsiOneValue.Add("Automation/Drive Interface"); + + break; + case PeripheralDeviceTypes.SCSISecurityManagerDevice: //0x13, + scsiOneValue.Add("Security Manager Device"); + + break; + case PeripheralDeviceTypes.SCSIZonedBlockDevice: //0x14 + scsiOneValue.Add("Host managed zoned block device"); + + break; + case PeripheralDeviceTypes.WellKnownDevice: //0x1E, + scsiOneValue.Add("Well known logical unit"); + + break; + case PeripheralDeviceTypes.UnknownDevice: //0x1F + scsiOneValue.Add("Unknown or no device type"); + + break; + default: + scsiOneValue.Add($"Unknown device type field value 0x{inquiry.PeripheralDeviceType:X2}"); + + break; + } + + switch((ANSIVersions)inquiry.ANSIVersion) + { + case ANSIVersions.ANSINoVersion: + scsiOneValue.Add("Device does not claim to comply with any SCSI ANSI standard"); + + break; + case ANSIVersions.ANSI1986Version: + scsiOneValue.Add("Device claims to comply with ANSI X3.131:1986 (SCSI-1)"); + + break; + case ANSIVersions.ANSI1994Version: + scsiOneValue.Add("Device claims to comply with ANSI X3.131:1994 (SCSI-2)"); + + break; + case ANSIVersions.ANSI1997Version: + scsiOneValue.Add("Device claims to comply with ANSI X3.301:1997 (SPC-1)"); + + break; + case ANSIVersions.ANSI2001Version: + scsiOneValue.Add("Device claims to comply with ANSI X3.351:2001 (SPC-2)"); + + break; + case ANSIVersions.ANSI2005Version: + scsiOneValue.Add("Device claims to comply with ANSI X3.408:2005 (SPC-3)"); + + break; + case ANSIVersions.ANSI2008Version: + scsiOneValue.Add("Device claims to comply with ANSI X3.408:2005 (SPC-4)"); + + break; + default: + scsiOneValue + .Add($"Device claims to comply with unknown SCSI ANSI standard value 0x{inquiry.ANSIVersion:X2})"); + + break; + } + + switch((ECMAVersions)inquiry.ECMAVersion) + { + case ECMAVersions.ECMANoVersion: + scsiOneValue.Add("Device does not claim to comply with any SCSI ECMA standard"); + + break; + case ECMAVersions.ECMA111: + scsiOneValue.Add("Device claims to comply ECMA-111: Small Computer System Interface SCSI"); + + break; + default: + scsiOneValue + .Add($"Device claims to comply with unknown SCSI ECMA standard value 0x{inquiry.ECMAVersion:X2})"); + + break; + } + + switch((ISOVersions)inquiry.ISOVersion) + { + case ISOVersions.ISONoVersion: + scsiOneValue.Add("Device does not claim to comply with any SCSI ISO/IEC standard"); + + break; + case ISOVersions.ISO1995Version: + scsiOneValue.Add("Device claims to comply with ISO/IEC 9316:1995"); + + break; + default: + scsiOneValue + .Add($"Device claims to comply with unknown SCSI ISO/IEC standard value 0x{inquiry.ISOVersion:X2})"); + + break; + } + + if(inquiry.RMB) scsiOneValue.Add("Device is removable"); + + if(inquiry.AERC) scsiOneValue.Add("Device supports Asynchronous Event Reporting Capability"); + + if(inquiry.TrmTsk) scsiOneValue.Add("Device supports TERMINATE TASK command"); + + if(inquiry.NormACA) scsiOneValue.Add("Device supports setting Normal ACA"); + + if(inquiry.HiSup) scsiOneValue.Add("Device supports LUN hierarchical addressing"); + + if(inquiry.SCCS) scsiOneValue.Add("Device contains an embedded storage array controller"); + + if(inquiry.ACC) scsiOneValue.Add("Device contains an Access Control Coordinator"); + + if(inquiry.ThreePC) scsiOneValue.Add("Device supports third-party copy commands"); + + if(inquiry.Protect) scsiOneValue.Add("Device supports protection information"); + + if(inquiry.BQue) scsiOneValue.Add("Device supports basic queueing"); + + if(inquiry.EncServ) scsiOneValue.Add("Device contains an embedded enclosure services component"); + + if(inquiry.MultiP) scsiOneValue.Add("Multi-port device"); + + if(inquiry.MChngr) scsiOneValue.Add("Device contains or is attached to a medium changer"); + + if(inquiry.ACKREQQ) scsiOneValue.Add("Device supports request and acknowledge handshakes"); + + if(inquiry.Addr32) scsiOneValue.Add("Device supports 32-bit wide SCSI addresses"); + + if(inquiry.Addr16) scsiOneValue.Add("Device supports 16-bit wide SCSI addresses"); + + if(inquiry.RelAddr) scsiOneValue.Add("Device supports relative addressing"); + + if(inquiry.WBus32) scsiOneValue.Add("Device supports 32-bit wide data transfers"); + + if(inquiry.WBus16) scsiOneValue.Add("Device supports 16-bit wide data transfers"); + + if(inquiry.Sync) scsiOneValue.Add("Device supports synchronous data transfer"); + + if(inquiry.Linked) scsiOneValue.Add("Device supports linked commands"); + + if(inquiry.TranDis) scsiOneValue.Add("Device supports CONTINUE TASK and TARGET TRANSFER DISABLE commands"); + + if(inquiry.QAS) scsiOneValue.Add("Device supports Quick Arbitration and Selection"); + + if(inquiry.CmdQue) scsiOneValue.Add("Device supports TCQ queue"); + + if(inquiry.IUS) scsiOneValue.Add("Device supports information unit transfers"); + + if(inquiry.SftRe) scsiOneValue.Add("Device implements RESET as a soft reset"); + + switch((TGPSValues)inquiry.TPGS) + { + case TGPSValues.NotSupported: + scsiOneValue.Add("Device does not support asymmetrical access"); + + break; + case TGPSValues.OnlyImplicit: + scsiOneValue.Add("Device only supports implicit asymmetrical access"); + + break; + case TGPSValues.OnlyExplicit: + scsiOneValue.Add("Device only supports explicit asymmetrical access"); + + break; + case TGPSValues.Both: + scsiOneValue.Add("Device supports implicit and explicit asymmetrical access"); + + break; + default: + scsiOneValue.Add($"Unknown value in TPGS field 0x{inquiry.TPGS:X2}"); + + break; + } + + switch((SPIClocking)inquiry.Clocking) + { + case SPIClocking.ST: + scsiOneValue.Add("Device supports only ST clocking"); + + break; + case SPIClocking.DT: + scsiOneValue.Add("Device supports only DT clocking"); + + break; + case SPIClocking.Reserved: + scsiOneValue.Add("Reserved value 0x02 found in SPI clocking field"); + + break; + case SPIClocking.STandDT: + scsiOneValue.Add("Device supports ST and DT clocking"); + + break; + default: + scsiOneValue.Add($"Unknown value in SPI clocking field 0x{inquiry.Clocking:X2}"); + + break; + } + + if(inquiry.VersionDescriptors == null) return scsiOneValue; + + foreach(ushort versionDescriptor in inquiry.VersionDescriptors) + { + switch(versionDescriptor) + { + case 0xFFFF: + case 0x0000: + break; + case 0x0020: + scsiOneValue.Add("Device complies with SAM (no version claimed)"); + + break; + case 0x003B: + scsiOneValue.Add("Device complies with SAM T10/0994-D revision 18"); + + break; + case 0x003C: + scsiOneValue.Add("Device complies with SAM ANSI INCITS 270-1996"); + + break; + case 0x0040: + scsiOneValue.Add("Device complies with SAM-2 (no version claimed)"); + + break; + case 0x0054: + scsiOneValue.Add("Device complies with SAM-2 T10/1157-D revision 23"); + + break; + case 0x0055: + scsiOneValue.Add("Device complies with SAM-2 T10/1157-D revision 24"); + + break; + case 0x005C: + scsiOneValue.Add("Device complies with SAM-2 ANSI INCITS 366-2003"); + + break; + case 0x005E: + scsiOneValue.Add("Device complies with SAM-2 ISO/IEC 14776-412"); + + break; + case 0x0060: + scsiOneValue.Add("Device complies with SAM-3 (no version claimed)"); + + break; + case 0x0062: + scsiOneValue.Add("Device complies with SAM-3 T10/1561-D revision 7"); + + break; + case 0x0075: + scsiOneValue.Add("Device complies with SAM-3 T10/1561-D revision 13"); + + break; + case 0x0076: + scsiOneValue.Add("Device complies with SAM-3 T10/1561-D revision 14"); + + break; + case 0x0077: + scsiOneValue.Add("Device complies with SAM-3 ANSI INCITS 402-2005"); + + break; + case 0x0080: + scsiOneValue.Add("Device complies with SAM-4 (no version claimed)"); + + break; + case 0x0087: + scsiOneValue.Add("Device complies with SAM-4 T10/1683-D revision 13"); + + break; + case 0x008B: + scsiOneValue.Add("Device complies with SAM-4 T10/1683-D revision 14"); + + break; + case 0x0090: + scsiOneValue.Add("Device complies with SAM-4 ANSI INCITS 447-2008"); + + break; + case 0x0092: + scsiOneValue.Add("Device complies with SAM-4 ISO/IEC 14776-414"); + + break; + case 0x00A0: + scsiOneValue.Add("Device complies with SAM-5 (no version claimed)"); + + break; + case 0x00A2: + scsiOneValue.Add("Device complies with SAM-5 T10/2104-D revision 4"); + + break; + case 0x00A4: + scsiOneValue.Add("Device complies with SAM-5 T10/2104-D revision 20"); + + break; + case 0x00A6: + scsiOneValue.Add("Device complies with SAM-5 T10/2104-D revision 21"); + + break; + case 0x00C0: + scsiOneValue.Add("Device complies with SAM-6 (no version claimed)"); + + break; + case 0x0120: + scsiOneValue.Add("Device complies with SPC (no version claimed)"); + + break; + case 0x013B: + scsiOneValue.Add("Device complies with SPC T10/0995-D revision 11a"); + + break; + case 0x013C: + scsiOneValue.Add("Device complies with SPC ANSI INCITS 301-1997"); + + break; + case 0x0140: + scsiOneValue.Add("Device complies with MMC (no version claimed)"); + + break; + case 0x015B: + scsiOneValue.Add("Device complies with MMC T10/1048-D revision 10a"); + + break; + case 0x015C: + scsiOneValue.Add("Device complies with MMC ANSI INCITS 304-1997"); + + break; + case 0x0160: + scsiOneValue.Add("Device complies with SCC (no version claimed)"); + + break; + case 0x017B: + scsiOneValue.Add("Device complies with SCC T10/1047-D revision 06c"); + + break; + case 0x017C: + scsiOneValue.Add("Device complies with SCC ANSI INCITS 276-1997"); + + break; + case 0x0180: + scsiOneValue.Add("Device complies with SBC (no version claimed)"); + + break; + case 0x019B: + scsiOneValue.Add("Device complies with SBC T10/0996-D revision 08c"); + + break; + case 0x019C: + scsiOneValue.Add("Device complies with SBC ANSI INCITS 306-1998"); + + break; + case 0x01A0: + scsiOneValue.Add("Device complies with SMC (no version claimed)"); + + break; + case 0x01BB: + scsiOneValue.Add("Device complies with SMC T10/0999-D revision 10a"); + + break; + case 0x01BC: + scsiOneValue.Add("Device complies with SMC ANSI INCITS 314-1998"); + + break; + case 0x01BE: + scsiOneValue.Add("Device complies with SMC ISO/IEC 14776-351"); + + break; + case 0x01C0: + scsiOneValue.Add("Device complies with SES (no version claimed)"); + + break; + case 0x01DB: + scsiOneValue.Add("Device complies with SES T10/1212-D revision 08b"); + + break; + case 0x01DC: + scsiOneValue.Add("Device complies with SES ANSI INCITS 305-1998"); + + break; + case 0x01DD: + scsiOneValue + .Add("Device complies with SES T10/1212 revision 08b w/ Amendment ANSI INCITS.305/AM1-2000"); + + break; + case 0x01DE: + scsiOneValue + .Add("Device complies with SES ANSI INCITS 305-1998 w/ Amendment ANSI INCITS.305/AM1-2000"); + + break; + case 0x01E0: + scsiOneValue.Add("Device complies with SCC-2 (no version claimed)"); + + break; + case 0x01FB: + scsiOneValue.Add("Device complies with SCC-2 T10/1125-D revision 04"); + + break; + case 0x01FC: + scsiOneValue.Add("Device complies with SCC-2 ANSI INCITS 318-1998"); + + break; + case 0x0200: + scsiOneValue.Add("Device complies with SSC (no version claimed)"); + + break; + case 0x0201: + scsiOneValue.Add("Device complies with SSC T10/0997-D revision 17"); + + break; + case 0x0207: + scsiOneValue.Add("Device complies with SSC T10/0997-D revision 22"); + + break; + case 0x021C: + scsiOneValue.Add("Device complies with SSC ANSI INCITS 335-2000"); + + break; + case 0x0220: + scsiOneValue.Add("Device complies with RBC (no version claimed)"); + + break; + case 0x0238: + scsiOneValue.Add("Device complies with RBC T10/1240-D revision 10a"); + + break; + case 0x023C: + scsiOneValue.Add("Device complies with RBC ANSI INCITS 330-2000"); + + break; + case 0x0240: + scsiOneValue.Add("Device complies with MMC-2 (no version claimed)"); + + break; + case 0x0255: + scsiOneValue.Add("Device complies with MMC-2 T10/1228-D revision 11"); + + break; + case 0x025B: + scsiOneValue.Add("Device complies with MMC-2 T10/1228-D revision 11a"); + + break; + case 0x025C: + scsiOneValue.Add("Device complies with MMC-2 ANSI INCITS 333-2000"); + + break; + case 0x0260: + scsiOneValue.Add("Device complies with SPC-2 (no version claimed)"); + + break; + case 0x0267: + scsiOneValue.Add("Device complies with SPC-2 T10/1236-D revision 12"); + + break; + case 0x0269: + scsiOneValue.Add("Device complies with SPC-2 T10/1236-D revision 18"); + + break; + case 0x0275: + scsiOneValue.Add("Device complies with SPC-2 T10/1236-D revision 19"); + + break; + case 0x0276: + scsiOneValue.Add("Device complies with SPC-2 T10/1236-D revision 20"); + + break; + case 0x0277: + scsiOneValue.Add("Device complies with SPC-2 ANSI INCITS 351-2001"); + + break; + case 0x0278: + scsiOneValue.Add("Device complies with SPC-2 ISO/IEC 14776-452"); + + break; + case 0x0280: + scsiOneValue.Add("Device complies with OCRW (no version claimed)"); + + break; + case 0x029E: + scsiOneValue.Add("Device complies with OCRW ISO/IEC 14776-381"); + + break; + case 0x02A0: + scsiOneValue.Add("Device complies with MMC-3 (no version claimed)"); + + break; + case 0x02B5: + scsiOneValue.Add("Device complies with MMC-3 T10/1363-D revision 9"); + + break; + case 0x02B6: + scsiOneValue.Add("Device complies with MMC-3 T10/1363-D revision 10g"); + + break; + case 0x02B8: + scsiOneValue.Add("Device complies with MMC-3 ANSI INCITS 360-2002"); + + break; + case 0x02E0: + scsiOneValue.Add("Device complies with SMC-2 (no version claimed)"); + + break; + case 0x02F5: + scsiOneValue.Add("Device complies with SMC-2 T10/1383-D revision 5"); + + break; + case 0x02FC: + scsiOneValue.Add("Device complies with SMC-2 T10/1383-D revision 6"); + + break; + case 0x02FD: + scsiOneValue.Add("Device complies with SMC-2 T10/1383-D revision 7"); + + break; + case 0x02FE: + scsiOneValue.Add("Device complies with SMC-2 ANSI INCITS 382-2004"); + + break; + case 0x0300: + scsiOneValue.Add("Device complies with SPC-3 (no version claimed)"); + + break; + case 0x0301: + scsiOneValue.Add("Device complies with SPC-3 T10/1416-D revision 7"); + + break; + case 0x0307: + scsiOneValue.Add("Device complies with SPC-3 T10/1416-D revision 21"); + + break; + case 0x030F: + scsiOneValue.Add("Device complies with SPC-3 T10/1416-D revision 22"); + + break; + case 0x0312: + scsiOneValue.Add("Device complies with SPC-3 T10/1416-D revision 23"); + + break; + case 0x0314: + scsiOneValue.Add("Device complies with SPC-3 ANSI INCITS 408-2005"); + + break; + case 0x0316: + scsiOneValue.Add("Device complies with SPC-3 ISO/IEC 14776-453"); + + break; + case 0x0320: + scsiOneValue.Add("Device complies with SBC-2 (no version claimed)"); + + break; + case 0x0322: + scsiOneValue.Add("Device complies with SBC-2 T10/1417-D revision 5a"); + + break; + case 0x0324: + scsiOneValue.Add("Device complies with SBC-2 T10/1417-D revision 15"); + + break; + case 0x033B: + scsiOneValue.Add("Device complies with SBC-2 T10/1417-D revision 16"); + + break; + case 0x033D: + scsiOneValue.Add("Device complies with SBC-2 ANSI INCITS 405-2005"); + + break; + case 0x033E: + scsiOneValue.Add("Device complies with SBC-2 ISO/IEC 14776-322"); + + break; + case 0x0340: + scsiOneValue.Add("Device complies with OSD (no version claimed)"); + + break; + case 0x0341: + scsiOneValue.Add("Device complies with OSD T10/1355-D revision 0"); + + break; + case 0x0342: + scsiOneValue.Add("Device complies with OSD T10/1355-D revision 7a"); + + break; + case 0x0343: + scsiOneValue.Add("Device complies with OSD T10/1355-D revision 8"); + + break; + case 0x0344: + scsiOneValue.Add("Device complies with OSD T10/1355-D revision 9"); + + break; + case 0x0355: + scsiOneValue.Add("Device complies with OSD T10/1355-D revision 10"); + + break; + case 0x0356: + scsiOneValue.Add("Device complies with OSD ANSI INCITS 400-2004"); + + break; + case 0x0360: + scsiOneValue.Add("Device complies with SSC-2 (no version claimed)"); + + break; + case 0x0374: + scsiOneValue.Add("Device complies with SSC-2 T10/1434-D revision 7"); + + break; + case 0x0375: + scsiOneValue.Add("Device complies with SSC-2 T10/1434-D revision 9"); + + break; + case 0x037D: + scsiOneValue.Add("Device complies with SSC-2 ANSI INCITS 380-2003"); + + break; + case 0x0380: + scsiOneValue.Add("Device complies with BCC (no version claimed)"); + + break; + case 0x03A0: + scsiOneValue.Add("Device complies with MMC-4 (no version claimed)"); + + break; + case 0x03B0: + scsiOneValue.Add("Device complies with MMC-4 T10/1545-D revision 5"); + + break; + case 0x03B1: + scsiOneValue.Add("Device complies with MMC-4 T10/1545-D revision 5a"); + + break; + case 0x03BD: + scsiOneValue.Add("Device complies with MMC-4 T10/1545-D revision 3"); + + break; + case 0x03BE: + scsiOneValue.Add("Device complies with MMC-4 T10/1545-D revision 3d"); + + break; + case 0x03BF: + scsiOneValue.Add("Device complies with MMC-4 ANSI INCITS 401-2005"); + + break; + case 0x03C0: + scsiOneValue.Add("Device complies with ADC (no version claimed)"); + + break; + case 0x03D5: + scsiOneValue.Add("Device complies with ADC T10/1558-D revision 6"); + + break; + case 0x03D6: + scsiOneValue.Add("Device complies with ADC T10/1558-D revision 7"); + + break; + case 0x03D7: + scsiOneValue.Add("Device complies with ADC ANSI INCITS 403-2005"); + + break; + case 0x03E0: + scsiOneValue.Add("Device complies with SES-2 (no version claimed)"); + + break; + case 0x03E1: + scsiOneValue.Add("Device complies with SES-2 T10/1559-D revision 16"); + + break; + case 0x03E7: + scsiOneValue.Add("Device complies with SES-2 T10/1559-D revision 19"); + + break; + case 0x03EB: + scsiOneValue.Add("Device complies with SES-2 T10/1559-D revision 20"); + + break; + case 0x03F0: + scsiOneValue.Add("Device complies with SES-2 ANSI INCITS 448-2008"); + + break; + case 0x03F2: + scsiOneValue.Add("Device complies with SES-2 ISO/IEC 14776-372"); + + break; + case 0x0400: + scsiOneValue.Add("Device complies with SSC-3 (no version claimed)"); + + break; + case 0x0403: + scsiOneValue.Add("Device complies with SSC-3 T10/1611-D revision 04a"); + + break; + case 0x0407: + scsiOneValue.Add("Device complies with SSC-3 T10/1611-D revision 05"); + + break; + case 0x0409: + scsiOneValue.Add("Device complies with SSC-3 ANSI INCITS 467-2011"); + + break; + case 0x040B: + scsiOneValue.Add("Device complies with SSC-3 ISO/IEC 14776-333:2013"); + + break; + case 0x0420: + scsiOneValue.Add("Device complies with MMC-5 (no version claimed)"); + + break; + case 0x042F: + scsiOneValue.Add("Device complies with MMC-5 T10/1675-D revision 03"); + + break; + case 0x0431: + scsiOneValue.Add("Device complies with MMC-5 T10/1675-D revision 03b"); + + break; + case 0x0432: + scsiOneValue.Add("Device complies with MMC-5 T10/1675-D revision 04"); + + break; + case 0x0434: + scsiOneValue.Add("Device complies with MMC-5 ANSI INCITS 430-2007"); + + break; + case 0x0440: + scsiOneValue.Add("Device complies with OSD-2 (no version claimed)"); + + break; + case 0x0444: + scsiOneValue.Add("Device complies with OSD-2 T10/1729-D revision 4"); + + break; + case 0x0446: + scsiOneValue.Add("Device complies with OSD-2 T10/1729-D revision 5"); + + break; + case 0x0448: + scsiOneValue.Add("Device complies with OSD-2 ANSI INCITS 458-2011"); + + break; + case 0x0460: + scsiOneValue.Add("Device complies with SPC-4 (no version claimed)"); + + break; + case 0x0461: + scsiOneValue.Add("Device complies with SPC-4 T10/BSR INCITS 513 revision 16"); + + break; + case 0x0462: + scsiOneValue.Add("Device complies with SPC-4 T10/BSR INCITS 513 revision 18"); + + break; + case 0x0463: + scsiOneValue.Add("Device complies with SPC-4 T10/BSR INCITS 513 revision 23"); + + break; + case 0x0466: + scsiOneValue.Add("Device complies with SPC-4 T10/BSR INCITS 513 revision 36"); + + break; + case 0x0468: + scsiOneValue.Add("Device complies with SPC-4 T10/BSR INCITS 513 revision 37"); + + break; + case 0x0469: + scsiOneValue.Add("Device complies with SPC-4 T10/BSR INCITS 513 revision 37a"); + + break; + case 0x046C: + scsiOneValue.Add("Device complies with SPC-4 ANSI INCITS 513-2015"); + + break; + case 0x0480: + scsiOneValue.Add("Device complies with SMC-3 (no version claimed)"); + + break; + case 0x0482: + scsiOneValue.Add("Device complies with SMC-3 T10/1730-D revision 15"); + + break; + case 0x0484: + scsiOneValue.Add("Device complies with SMC-3 T10/1730-D revision 16"); + + break; + case 0x0486: + scsiOneValue.Add("Device complies with SMC-3 ANSI INCITS 484-2012"); + + break; + case 0x04A0: + scsiOneValue.Add("Device complies with ADC-2 (no version claimed)"); + + break; + case 0x04A7: + scsiOneValue.Add("Device complies with ADC-2 T10/1741-D revision 7"); + + break; + case 0x04AA: + scsiOneValue.Add("Device complies with ADC-2 T10/1741-D revision 8"); + + break; + case 0x04AC: + scsiOneValue.Add("Device complies with ADC-2 ANSI INCITS 441-2008"); + + break; + case 0x04C0: + scsiOneValue.Add("Device complies with SBC-3 (no version claimed)"); + + break; + case 0x04C3: + scsiOneValue.Add("Device complies with SBC-3 T10/BSR INCITS 514 revision 35"); + + break; + case 0x04C5: + scsiOneValue.Add("Device complies with SBC-3 T10/BSR INCITS 514 revision 36"); + + break; + case 0x04C8: + scsiOneValue.Add("Device complies with SBC-3 ANSI INCITS 514-2014"); + + break; + case 0x04E0: + scsiOneValue.Add("Device complies with MMC-6 (no version claimed)"); + + break; + case 0x04E3: + scsiOneValue.Add("Device complies with MMC-6 T10/1836-D revision 02b"); + + break; + case 0x04E5: + scsiOneValue.Add("Device complies with MMC-6 T10/1836-D revision 02g"); + + break; + case 0x04E6: + scsiOneValue.Add("Device complies with MMC-6 ANSI INCITS 468-2010"); + + break; + case 0x04E7: + scsiOneValue + .Add("Device complies with MMC-6 ANSI INCITS 468-2010 + MMC-6/AM1 ANSI INCITS 468-2010/AM 1"); + + break; + case 0x0500: + scsiOneValue.Add("Device complies with ADC-3 (no version claimed)"); + + break; + case 0x0502: + scsiOneValue.Add("Device complies with ADC-3 T10/1895-D revision 04"); + + break; + case 0x0504: + scsiOneValue.Add("Device complies with ADC-3 T10/1895-D revision 05"); + + break; + case 0x0506: + scsiOneValue.Add("Device complies with ADC-3 T10/1895-D revision 05a"); + + break; + case 0x050A: + scsiOneValue.Add("Device complies with ADC-3 ANSI INCITS 497-2012"); + + break; + case 0x0520: + scsiOneValue.Add("Device complies with SSC-4 (no version claimed)"); + + break; + case 0x0523: + scsiOneValue.Add("Device complies with SSC-4 T10/BSR INCITS 516 revision 2"); + + break; + case 0x0525: + scsiOneValue.Add("Device complies with SSC-4 T10/BSR INCITS 516 revision 3"); + + break; + case 0x0527: + scsiOneValue.Add("Device complies with SSC-4 ANSI INCITS 516-2013"); + + break; + case 0x0560: + scsiOneValue.Add("Device complies with OSD-3 (no version claimed)"); + + break; + case 0x0580: + scsiOneValue.Add("Device complies with SES-3 (no version claimed)"); + + break; + case 0x05A0: + scsiOneValue.Add("Device complies with SSC-5 (no version claimed)"); + + break; + case 0x05C0: + scsiOneValue.Add("Device complies with SPC-5 (no version claimed)"); + + break; + case 0x05E0: + scsiOneValue.Add("Device complies with SFSC (no version claimed)"); + + break; + case 0x05E3: + scsiOneValue.Add("Device complies with SFSC BSR INCITS 501 revision 01"); + + break; + case 0x0600: + scsiOneValue.Add("Device complies with SBC-4 (no version claimed)"); + + break; + case 0x0620: + scsiOneValue.Add("Device complies with ZBC (no version claimed)"); + + break; + case 0x0622: + scsiOneValue.Add("Device complies with ZBC BSR INCITS 536 revision 02"); + + break; + case 0x0640: + scsiOneValue.Add("Device complies with ADC-4 (no version claimed)"); + + break; + case 0x0820: + scsiOneValue.Add("Device complies with SSA-TL2 (no version claimed)"); + + break; + case 0x083B: + scsiOneValue.Add("Device complies with SSA-TL2 T10.1/1147-D revision 05b"); + + break; + case 0x083C: + scsiOneValue.Add("Device complies with SSA-TL2 ANSI INCITS 308-1998"); + + break; + case 0x0840: + scsiOneValue.Add("Device complies with SSA-TL1 (no version claimed)"); + + break; + case 0x085B: + scsiOneValue.Add("Device complies with SSA-TL1 T10.1/0989-D revision 10b"); + + break; + case 0x085C: + scsiOneValue.Add("Device complies with SSA-TL1 ANSI INCITS 295-1996"); + + break; + case 0x0860: + scsiOneValue.Add("Device complies with SSA-S3P (no version claimed)"); + + break; + case 0x087B: + scsiOneValue.Add("Device complies with SSA-S3P T10.1/1051-D revision 05b"); + + break; + case 0x087C: + scsiOneValue.Add("Device complies with SSA-S3P ANSI INCITS 309-1998"); + + break; + case 0x0880: + scsiOneValue.Add("Device complies with SSA-S2P (no version claimed)"); + + break; + case 0x089B: + scsiOneValue.Add("Device complies with SSA-S2P T10.1/1121-D revision 07b"); + + break; + case 0x089C: + scsiOneValue.Add("Device complies with SSA-S2P ANSI INCITS 294-1996"); + + break; + case 0x08A0: + scsiOneValue.Add("Device complies with SIP (no version claimed)"); + + break; + case 0x08BB: + scsiOneValue.Add("Device complies with SIP T10/0856-D revision 10"); + + break; + case 0x08BC: + scsiOneValue.Add("Device complies with SIP ANSI INCITS 292-1997"); + + break; + case 0x08C0: + scsiOneValue.Add("Device complies with FCP (no version claimed)"); + + break; + case 0x08DB: + scsiOneValue.Add("Device complies with FCP T10/0993-D revision 12"); + + break; + case 0x08DC: + scsiOneValue.Add("Device complies with FCP ANSI INCITS 269-1996"); + + break; + case 0x08E0: + scsiOneValue.Add("Device complies with SBP-2 (no version claimed)"); + + break; + case 0x08FB: + scsiOneValue.Add("Device complies with SBP-2 T10/1155-D revision 04"); + + break; + case 0x08FC: + scsiOneValue.Add("Device complies with SBP-2 ANSI INCITS 325-1998"); + + break; + case 0x0900: + scsiOneValue.Add("Device complies with FCP-2 (no version claimed)"); + + break; + case 0x0901: + scsiOneValue.Add("Device complies with FCP-2 T10/1144-D revision 4"); + + break; + case 0x0915: + scsiOneValue.Add("Device complies with FCP-2 T10/1144-D revision 7"); + + break; + case 0x0916: + scsiOneValue.Add("Device complies with FCP-2 T10/1144-D revision 7a"); + + break; + case 0x0917: + scsiOneValue.Add("Device complies with FCP-2 ANSI INCITS 350-2003"); + + break; + case 0x0918: + scsiOneValue.Add("Device complies with FCP-2 T10/1144-D revision 8"); + + break; + case 0x0920: + scsiOneValue.Add("Device complies with SST (no version claimed)"); + + break; + case 0x0935: + scsiOneValue.Add("Device complies with SST T10/1380-D revision 8b"); + + break; + case 0x0940: + scsiOneValue.Add("Device complies with SRP (no version claimed)"); + + break; + case 0x0954: + scsiOneValue.Add("Device complies with SRP T10/1415-D revision 10"); + + break; + case 0x0955: + scsiOneValue.Add("Device complies with SRP T10/1415-D revision 16a"); + + break; + case 0x095C: + scsiOneValue.Add("Device complies with SRP ANSI INCITS 365-2002"); + + break; + case 0x0960: + scsiOneValue.Add("Device complies with iSCSI (no version claimed)"); + + break; + case 0x0961: + case 0x0962: + case 0x0963: + case 0x0964: + case 0x0965: + case 0x0966: + case 0x0967: + case 0x0968: + case 0x0969: + case 0x096A: + case 0x096B: + case 0x096C: + case 0x096D: + case 0x096E: + case 0x096F: + case 0x0970: + case 0x0971: + case 0x0972: + case 0x0973: + case 0x0974: + case 0x0975: + case 0x0976: + case 0x0977: + case 0x0978: + case 0x0979: + case 0x097A: + case 0x097B: + case 0x097C: + case 0x097D: + case 0x097E: + case 0x097F: + scsiOneValue.Add($"Device complies with iSCSI revision {versionDescriptor & 0x1F}"); + + break; + case 0x0980: + scsiOneValue.Add("Device complies with SBP-3 (no version claimed)"); + + break; + case 0x0982: + scsiOneValue.Add("Device complies with SBP-3 T10/1467-D revision 1f"); + + break; + case 0x0994: + scsiOneValue.Add("Device complies with SBP-3 T10/1467-D revision 3"); + + break; + case 0x099A: + scsiOneValue.Add("Device complies with SBP-3 T10/1467-D revision 4"); + + break; + case 0x099B: + scsiOneValue.Add("Device complies with SBP-3 T10/1467-D revision 5"); + + break; + case 0x099C: + scsiOneValue.Add("Device complies with SBP-3 ANSI INCITS 375-2004"); + + break; + case 0x09C0: + scsiOneValue.Add("Device complies with ADP (no version claimed)"); + + break; + case 0x09E0: + scsiOneValue.Add("Device complies with ADT (no version claimed)"); + + break; + case 0x09F9: + scsiOneValue.Add("Device complies with ADT T10/1557-D revision 11"); + + break; + case 0x09FA: + scsiOneValue.Add("Device complies with ADT T10/1557-D revision 14"); + + break; + case 0x09FD: + scsiOneValue.Add("Device complies with ADT ANSI INCITS 406-2005"); + + break; + case 0x0A00: + scsiOneValue.Add("Device complies with FCP-3 (no version claimed)"); + + break; + case 0x0A07: + scsiOneValue.Add("Device complies with FCP-3 T10/1560-D revision 3f"); + + break; + case 0x0A0F: + scsiOneValue.Add("Device complies with FCP-3 T10/1560-D revision 4"); + + break; + case 0x0A11: + scsiOneValue.Add("Device complies with FCP-3 ANSI INCITS 416-2006"); + + break; + case 0x0A1C: + scsiOneValue.Add("Device complies with FCP-3 ISO/IEC 14776-223"); + + break; + case 0x0A20: + scsiOneValue.Add("Device complies with ADT-2 (no version claimed)"); + + break; + case 0x0A22: + scsiOneValue.Add("Device complies with ADT-2 T10/1742-D revision 06"); + + break; + case 0x0A27: + scsiOneValue.Add("Device complies with ADT-2 T10/1742-D revision 08"); + + break; + case 0x0A28: + scsiOneValue.Add("Device complies with ADT-2 T10/1742-D revision 09"); + + break; + case 0x0A2B: + scsiOneValue.Add("Device complies with ADT-2 ANSI INCITS 472-2011"); + + break; + case 0x0A40: + scsiOneValue.Add("Device complies with FCP-4 (no version claimed)"); + + break; + case 0x0A42: + scsiOneValue.Add("Device complies with FCP-4 T10/1828-D revision 01"); + + break; + case 0x0A44: + scsiOneValue.Add("Device complies with FCP-4 T10/1828-D revision 02"); + + break; + case 0x0A45: + scsiOneValue.Add("Device complies with FCP-4 T10/1828-D revision 02b"); + + break; + case 0x0A46: + scsiOneValue.Add("Device complies with FCP-4 ANSI INCITS 481-2012"); + + break; + case 0x0A60: + scsiOneValue.Add("Device complies with ADT-3 (no version claimed)"); + + break; + case 0x0AA0: + scsiOneValue.Add("Device complies with SPI (no version claimed)"); + + break; + case 0x0AB9: + scsiOneValue.Add("Device complies with SPI T10/0855-D revision 15a"); + + break; + case 0x0ABA: + scsiOneValue.Add("Device complies with SPI ANSI INCITS 253-1995"); + + break; + case 0x0ABB: + scsiOneValue.Add("Device complies with SPI T10/0855-D revision 15a with SPI Amnd revision 3a"); + + break; + case 0x0ABC: + scsiOneValue + .Add("Device complies with SPI ANSI INCITS 253-1995 with SPI Amnd ANSI INCITS 253/AM1-1998"); + + break; + case 0x0AC0: + scsiOneValue.Add("Device complies with Fast-20 (no version claimed)"); + + break; + case 0x0ADB: + scsiOneValue.Add("Device complies with Fast-20 T10/1071 revision 06"); + + break; + case 0x0ADC: + scsiOneValue.Add("Device complies with Fast-20 ANSI INCITS 277-1996"); + + break; + case 0x0AE0: + scsiOneValue.Add("Device complies with SPI-2 (no version claimed)"); + + break; + case 0x0AFB: + scsiOneValue.Add("Device complies with SPI-2 T10/1142-D revision 20b"); + + break; + case 0x0AFC: + scsiOneValue.Add("Device complies with SPI-2 ANSI INCITS 302-1999"); + + break; + case 0x0B00: + scsiOneValue.Add("Device complies with SPI-3 (no version claimed)"); + + break; + case 0x0B18: + scsiOneValue.Add("Device complies with SPI-3 T10/1302-D revision 10"); + + break; + case 0x0B19: + scsiOneValue.Add("Device complies with SPI-3 T10/1302-D revision 13a"); + + break; + case 0x0B1A: + scsiOneValue.Add("Device complies with SPI-3 T10/1302-D revision 14"); + + break; + case 0x0B1C: + scsiOneValue.Add("Device complies with SPI-3 ANSI INCITS 336-2000"); + + break; + case 0x0B20: + scsiOneValue.Add("Device complies with EPI (no version claimed)"); + + break; + case 0x0B3B: + scsiOneValue.Add("Device complies with EPI T10/1134 revision 16"); + + break; + case 0x0B3C: + scsiOneValue.Add("Device complies with EPI ANSI INCITS TR-23 1999"); + + break; + case 0x0B40: + scsiOneValue.Add("Device complies with SPI-4 (no version claimed)"); + + break; + case 0x0B54: + scsiOneValue.Add("Device complies with SPI-4 T10/1365-D revision 7"); + + break; + case 0x0B55: + scsiOneValue.Add("Device complies with SPI-4 T10/1365-D revision 9"); + + break; + case 0x0B56: + scsiOneValue.Add("Device complies with SPI-4 ANSI INCITS 362-2002"); + + break; + case 0x0B59: + scsiOneValue.Add("Device complies with SPI-4 T10/1365-D revision 10"); + + break; + case 0x0B60: + scsiOneValue.Add("Device complies with SPI-5 (no version claimed)"); + + break; + case 0x0B79: + scsiOneValue.Add("Device complies with SPI-5 T10/1525-D revision 3"); + + break; + case 0x0B7A: + scsiOneValue.Add("Device complies with SPI-5 T10/1525-D revision 5"); + + break; + case 0x0B7B: + scsiOneValue.Add("Device complies with SPI-5 T10/1525-D revision 6"); + + break; + case 0x0B7C: + scsiOneValue.Add("Device complies with SPI-5 ANSI INCITS 367-2003"); + + break; + case 0x0BE0: + scsiOneValue.Add("Device complies with SAS (no version claimed)"); + + break; + case 0x0BE1: + scsiOneValue.Add("Device complies with SAS T10/1562-D revision 01"); + + break; + case 0x0BF5: + scsiOneValue.Add("Device complies with SAS T10/1562-D revision 03"); + + break; + case 0x0BFA: + scsiOneValue.Add("Device complies with SAS T10/1562-D revision 04"); + + break; + case 0x0BFB: + scsiOneValue.Add("Device complies with SAS T10/1562-D revision 04"); + + break; + case 0x0BFC: + scsiOneValue.Add("Device complies with SAS T10/1562-D revision 05"); + + break; + case 0x0BFD: + scsiOneValue.Add("Device complies with SAS ANSI INCITS 376-2003"); + + break; + case 0x0C00: + scsiOneValue.Add("Device complies with SAS-1.1 (no version claimed)"); + + break; + case 0x0C07: + scsiOneValue.Add("Device complies with SAS-1.1 T10/1601-D revision 9"); + + break; + case 0x0C0F: + scsiOneValue.Add("Device complies with SAS-1.1 T10/1601-D revision 10"); + + break; + case 0x0C11: + scsiOneValue.Add("Device complies with SAS-1.1 ANSI INCITS 417-2006"); + + break; + case 0x0C12: + scsiOneValue.Add("Device complies with SAS-1.1 ISO/IEC 14776-151"); + + break; + case 0x0C20: + scsiOneValue.Add("Device complies with SAS-2 (no version claimed)"); + + break; + case 0x0C23: + scsiOneValue.Add("Device complies with SAS-2 T10/1760-D revision 14"); + + break; + case 0x0C27: + scsiOneValue.Add("Device complies with SAS-2 T10/1760-D revision 15"); + + break; + case 0x0C28: + scsiOneValue.Add("Device complies with SAS-2 T10/1760-D revision 16"); + + break; + case 0x0C2A: + scsiOneValue.Add("Device complies with SAS-2 ANSI INCITS 457-2010"); + + break; + case 0x0C40: + scsiOneValue.Add("Device complies with SAS-2.1 (no version claimed)"); + + break; + case 0x0C48: + scsiOneValue.Add("Device complies with SAS-2.1 T10/2125-D revision 04"); + + break; + case 0x0C4A: + scsiOneValue.Add("Device complies with SAS-2.1 T10/2125-D revision 06"); + + break; + case 0x0C4B: + scsiOneValue.Add("Device complies with SAS-2.1 T10/2125-D revision 07"); + + break; + case 0x0C4E: + scsiOneValue.Add("Device complies with SAS-2.1 ANSI INCITS 478-2011"); + + break; + case 0x0C4F: + scsiOneValue + .Add("Device complies with SAS-2.1 ANSI INCITS 478-2011 w/ Amnd 1 ANSI INCITS 478/AM1-2014"); + + break; + case 0x0C52: + scsiOneValue.Add("Device complies with SAS-2.1 ISO/IEC 14776-153"); + + break; + case 0x0C60: + scsiOneValue.Add("Device complies with SAS-3 (no version claimed)"); + + break; + case 0x0C63: + scsiOneValue.Add("Device complies with SAS-3 T10/BSR INCITS 519 revision 05a"); + + break; + case 0x0C65: + scsiOneValue.Add("Device complies with SAS-3 T10/BSR INCITS 519 revision 06"); + + break; + case 0x0C68: + scsiOneValue.Add("Device complies with SAS-3 ANSI INCITS 519-2014"); + + break; + case 0x0C80: + scsiOneValue.Add("Device complies with SAS-4 (no version claimed)"); + + break; + case 0x0D20: + scsiOneValue.Add("Device complies with FC-PH (no version claimed)"); + + break; + case 0x0D3B: + scsiOneValue.Add("Device complies with FC-PH ANSI INCITS 230-1994"); + + break; + case 0x0D3C: + scsiOneValue + .Add("Device complies with FC-PH ANSI INCITS 230-1994 with Amnd 1 ANSI INCITS 230/AM1-1996"); + + break; + case 0x0D40: + scsiOneValue.Add("Device complies with FC-AL (no version claimed)"); + + break; + case 0x0D5C: + scsiOneValue.Add("Device complies with FC-AL ANSI INCITS 272-1996"); + + break; + case 0x0D60: + scsiOneValue.Add("Device complies with FC-AL-2 (no version claimed)"); + + break; + case 0x0D61: + scsiOneValue.Add("Device complies with FC-AL-2 T11/1133-D revision 7.0"); + + break; + case 0x0D63: + scsiOneValue.Add("Device complies with FC-AL-2 ANSI INCITS 332-1999 with AM1-2003 & AM2-2006"); + + break; + case 0x0D64: + scsiOneValue.Add("Device complies with FC-AL-2 ANSI INCITS 332-1999 with Amnd 2 AM2-2006"); + + break; + case 0x0D65: + scsiOneValue.Add("Device complies with FC-AL-2 ISO/IEC 14165-122 with AM1 & AM2"); + + break; + case 0x0D7C: + scsiOneValue.Add("Device complies with FC-AL-2 ANSI INCITS 332-1999"); + + break; + case 0x0D7D: + scsiOneValue.Add("Device complies with FC-AL-2 ANSI INCITS 332-1999 with Amnd 1 AM1-2003"); + + break; + case 0x0D80: + scsiOneValue.Add("Device complies with FC-PH-3 (no version claimed)"); + + break; + case 0x0D9C: + scsiOneValue.Add("Device complies with FC-PH-3 ANSI INCITS 303-1998"); + + break; + case 0x0DA0: + scsiOneValue.Add("Device complies with FC-FS (no version claimed)"); + + break; + case 0x0DB7: + scsiOneValue.Add("Device complies with FC-FS T11/1331-D revision 1.2"); + + break; + case 0x0DB8: + scsiOneValue.Add("Device complies with FC-FS T11/1331-D revision 1.7"); + + break; + case 0x0DBC: + scsiOneValue.Add("Device complies with FC-FS ANSI INCITS 373-2003"); + + break; + case 0x0DBD: + scsiOneValue.Add("Device complies with FC-FS ISO/IEC 14165-251"); + + break; + case 0x0DC0: + scsiOneValue.Add("Device complies with FC-PI (no version claimed)"); + + break; + case 0x0DDC: + scsiOneValue.Add("Device complies with FC-PI ANSI INCITS 352-2002"); + + break; + case 0x0DE0: + scsiOneValue.Add("Device complies with FC-PI-2 (no version claimed)"); + + break; + case 0x0DE2: + scsiOneValue.Add("Device complies with FC-PI-2 T11/1506-D revision 5.0"); + + break; + case 0x0DE4: + scsiOneValue.Add("Device complies with FC-PI-2 ANSI INCITS 404-2006"); + + break; + case 0x0E00: + scsiOneValue.Add("Device complies with FC-FS-2 (no version claimed)"); + + break; + case 0x0E02: + scsiOneValue.Add("Device complies with FC-FS-2 ANSI INCITS 242-2007"); + + break; + case 0x0E03: + scsiOneValue + .Add("Device complies with FC-FS-2 ANSI INCITS 242-2007 with AM1 ANSI INCITS 242/AM1-2007"); + + break; + case 0x0E20: + scsiOneValue.Add("Device complies with FC-LS (no version claimed)"); + + break; + case 0x0E21: + scsiOneValue.Add("Device complies with FC-LS T11/1620-D revision 1.62"); + + break; + case 0x0E29: + scsiOneValue.Add("Device complies with FC-LS ANSI INCITS 433-2007"); + + break; + case 0x0E40: + scsiOneValue.Add("Device complies with FC-SP (no version claimed)"); + + break; + case 0x0E42: + scsiOneValue.Add("Device complies with FC-SP T11/1570-D revision 1.6"); + + break; + case 0x0E45: + scsiOneValue.Add("Device complies with FC-SP ANSI INCITS 426-2007"); + + break; + case 0x0E60: + scsiOneValue.Add("Device complies with FC-PI-3 (no version claimed)"); + + break; + case 0x0E62: + scsiOneValue.Add("Device complies with FC-PI-3 T11/1625-D revision 2.0"); + + break; + case 0x0E68: + scsiOneValue.Add("Device complies with FC-PI-3 T11/1625-D revision 2.1"); + + break; + case 0x0E6A: + scsiOneValue.Add("Device complies with FC-PI-3 T11/1625-D revision 4.0"); + + break; + case 0x0E6E: + scsiOneValue.Add("Device complies with FC-PI-3 ANSI INCITS 460-2011"); + + break; + case 0x0E80: + scsiOneValue.Add("Device complies with FC-PI-4 (no version claimed)"); + + break; + case 0x0E82: + scsiOneValue.Add("Device complies with FC-PI-4 T11/1647-D revision 8.0"); + + break; + case 0x0E88: + scsiOneValue.Add("Device complies with FC-PI-4 ANSI INCITS 450-2009"); + + break; + case 0x0EA0: + scsiOneValue.Add("Device complies with FC 10GFC (no version claimed)"); + + break; + case 0x0EA2: + scsiOneValue.Add("Device complies with FC 10GFC ANSI INCITS 364-2003"); + + break; + case 0x0EA3: + scsiOneValue.Add("Device complies with FC 10GFC ISO/IEC 14165-116"); + + break; + case 0x0EA5: + scsiOneValue.Add("Device complies with FC 10GFC ISO/IEC 14165-116 with AM1"); + + break; + case 0x0EA6: + scsiOneValue + .Add("Device complies with FC 10GFC ANSI INCITS 364-2003 with AM1 ANSI INCITS 364/AM1-2007"); + + break; + case 0x0EC0: + scsiOneValue.Add("Device complies with FC-SP-2 (no version claimed)"); + + break; + case 0x0EE0: + scsiOneValue.Add("Device complies with FC-FS-3 (no version claimed)"); + + break; + case 0x0EE2: + scsiOneValue.Add("Device complies with FC-FS-3 T11/1861-D revision 0.9"); + + break; + case 0x0EE7: + scsiOneValue.Add("Device complies with FC-FS-3 T11/1861-D revision 1.0"); + + break; + case 0x0EE9: + scsiOneValue.Add("Device complies with FC-FS-3 T11/1861-D revision 1.10"); + + break; + case 0x0EEB: + scsiOneValue.Add("Device complies with FC-FS-3 ANSI INCITS 470-2011"); + + break; + case 0x0F00: + scsiOneValue.Add("Device complies with FC-LS-2 (no version claimed)"); + + break; + case 0x0F03: + scsiOneValue.Add("Device complies with FC-LS-2 T11/2103-D revision 2.11"); + + break; + case 0x0F05: + scsiOneValue.Add("Device complies with FC-LS-2 T11/2103-D revision 2.21"); + + break; + case 0x0F07: + scsiOneValue.Add("Device complies with FC-LS-2 ANSI INCITS 477-2011"); + + break; + case 0x0F20: + scsiOneValue.Add("Device complies with FC-PI-5 (no version claimed)"); + + break; + case 0x0F27: + scsiOneValue.Add("Device complies with FC-PI-5 T11/2118-D revision 2.00"); + + break; + case 0x0F28: + scsiOneValue.Add("Device complies with FC-PI-5 T11/2118-D revision 3.00"); + + break; + case 0x0F2A: + scsiOneValue.Add("Device complies with FC-PI-5 T11/2118-D revision 6.00"); + + break; + case 0x0F2B: + scsiOneValue.Add("Device complies with FC-PI-5 T11/2118-D revision 6.10"); + + break; + case 0x0F2E: + scsiOneValue.Add("Device complies with FC-PI-5 ANSI INCITS 479-2011"); + + break; + case 0x0F40: + scsiOneValue.Add("Device complies with FC-PI-6 (no version claimed)"); + + break; + case 0x0F60: + scsiOneValue.Add("Device complies with FC-FS-4 (no version claimed)"); + + break; + case 0x0F80: + scsiOneValue.Add("Device complies with FC-LS-3 (no version claimed)"); + + break; + case 0x12A0: + scsiOneValue.Add("Device complies with FC-SCM (no version claimed)"); + + break; + case 0x12A3: + scsiOneValue.Add("Device complies with FC-SCM T11/1824DT revision 1.0"); + + break; + case 0x12A5: + scsiOneValue.Add("Device complies with FC-SCM T11/1824DT revision 1.1"); + + break; + case 0x12A7: + scsiOneValue.Add("Device complies with FC-SCM T11/1824DT revision 1.4"); + + break; + case 0x12AA: + scsiOneValue.Add("Device complies with FC-SCM INCITS TR-47 2012"); + + break; + case 0x12C0: + scsiOneValue.Add("Device complies with FC-DA-2 (no version claimed)"); + + break; + case 0x12C3: + scsiOneValue.Add("Device complies with FC-DA-2 T11/1870DT revision 1.04"); + + break; + case 0x12C5: + scsiOneValue.Add("Device complies with FC-DA-2 T11/1870DT revision 1.06"); + + break; + case 0x12C9: + scsiOneValue.Add("Device complies with FC-DA-2 INCITS TR-49 2012"); + + break; + case 0x12E0: + scsiOneValue.Add("Device complies with FC-DA (no version claimed)"); + + break; + case 0x12E2: + scsiOneValue.Add("Device complies with FC-DA T11/1513-DT revision 3.1"); + + break; + case 0x12E8: + scsiOneValue.Add("Device complies with FC-DA ANSI INCITS TR-36 2004"); + + break; + case 0x12E9: + scsiOneValue.Add("Device complies with FC-DA ISO/IEC 14165-341"); + + break; + case 0x1300: + scsiOneValue.Add("Device complies with FC-Tape (no version claimed)"); + + break; + case 0x1301: + scsiOneValue.Add("Device complies with FC-Tape T11/1315 revision 1.16"); + + break; + case 0x131B: + scsiOneValue.Add("Device complies with FC-Tape T11/1315 revision 1.17"); + + break; + case 0x131C: + scsiOneValue.Add("Device complies with FC-Tape ANSI INCITS TR-24 1999"); + + break; + case 0x1320: + scsiOneValue.Add("Device complies with FC-FLA (no version claimed)"); + + break; + case 0x133B: + scsiOneValue.Add("Device complies with FC-FLA T11/1235 revision 7"); + + break; + case 0x133C: + scsiOneValue.Add("Device complies with FC-FLA ANSI INCITS TR-20 1998"); + + break; + case 0x1340: + scsiOneValue.Add("Device complies with FC-PLDA (no version claimed)"); + + break; + case 0x135B: + scsiOneValue.Add("Device complies with FC-PLDA T11/1162 revision 2.1"); + + break; + case 0x135C: + scsiOneValue.Add("Device complies with FC-PLDA ANSI INCITS TR-19 1998"); + + break; + case 0x1360: + scsiOneValue.Add("Device complies with SSA-PH2 (no version claimed)"); + + break; + case 0x137B: + scsiOneValue.Add("Device complies with SSA-PH2 T10.1/1145-D revision 09c"); + + break; + case 0x137C: + scsiOneValue.Add("Device complies with SSA-PH2 ANSI INCITS 293-1996"); + + break; + case 0x1380: + scsiOneValue.Add("Device complies with SSA-PH3 (no version claimed)"); + + break; + case 0x139B: + scsiOneValue.Add("Device complies with SSA-PH3 T10.1/1146-D revision 05b"); + + break; + case 0x139C: + scsiOneValue.Add("Device complies with SSA-PH3 ANSI INCITS 307-1998"); + + break; + case 0x14A0: + scsiOneValue.Add("Device complies with IEEE 1394 (no version claimed)"); + + break; + case 0x14BD: + scsiOneValue.Add("Device complies with ANSI IEEE 1394-1995"); + + break; + case 0x14C0: + scsiOneValue.Add("Device complies with IEEE 1394a (no version claimed)"); + + break; + case 0x14E0: + scsiOneValue.Add("Device complies with IEEE 1394b (no version claimed)"); + + break; + case 0x15E0: + scsiOneValue.Add("Device complies with ATA/ATAPI-6 (no version claimed)"); + + break; + case 0x15FD: + scsiOneValue.Add("Device complies with ATA/ATAPI-6 ANSI INCITS 361-2002"); + + break; + case 0x1600: + scsiOneValue.Add("Device complies with ATA/ATAPI-7 (no version claimed)"); + + break; + case 0x1602: + scsiOneValue.Add("Device complies with ATA/ATAPI-7 T13/1532-D revision 3"); + + break; + case 0x161C: + scsiOneValue.Add("Device complies with ATA/ATAPI-7 ANSI INCITS 397-2005"); + + break; + case 0x161E: + scsiOneValue.Add("Device complies with ATA/ATAPI-7 ISO/IEC 24739"); + + break; + case 0x1620: + scsiOneValue.Add("Device complies with ATA/ATAPI-8 ATA8-AAM (no version claimed)"); + + break; + case 0x1621: + scsiOneValue + .Add("Device complies with ATA/ATAPI-8 ATA8-APT Parallel Transport (no version claimed)"); + + break; + case 0x1622: + scsiOneValue.Add("Device complies with ATA/ATAPI-8 ATA8-AST Serial Transport (no version claimed)"); + + break; + case 0x1623: + scsiOneValue + .Add("Device complies with ATA/ATAPI-8 ATA8-ACS ATA/ATAPI Command Set (no version claimed)"); + + break; + case 0x1628: + scsiOneValue.Add("Device complies with ATA/ATAPI-8 ATA8-AAM ANSI INCITS 451-2008"); + + break; + case 0x162A: + scsiOneValue.Add("Device complies with ATA/ATAPI-8 ATA8-ACS ANSI INCITS 452-2009 w/ Amendment 1"); + + break; + case 0x1728: + scsiOneValue.Add("Device complies with Universal Serial Bus Specification, Revision 1.1"); + + break; + case 0x1729: + scsiOneValue.Add("Device complies with Universal Serial Bus Specification, Revision 2.0"); + + break; + case 0x1730: + scsiOneValue.Add("Device complies with USB Mass Storage Class Bulk-Only Transport, Revision 1.0"); + + break; + case 0x1740: + scsiOneValue.Add("Device complies with UAS (no version claimed)"); + + break; + case 0x1743: + scsiOneValue.Add("Device complies with UAS T10/2095-D revision 02"); + + break; + case 0x1747: + scsiOneValue.Add("Device complies with UAS T10/2095-D revision 04"); + + break; + case 0x1748: + scsiOneValue.Add("Device complies with UAS ANSI INCITS 471-2010"); + + break; + case 0x1749: + scsiOneValue.Add("Device complies with UAS ISO/IEC 14776-251:2014"); + + break; + case 0x1761: + scsiOneValue.Add("Device complies with ACS-2 (no version claimed)"); + + break; + case 0x1762: + scsiOneValue.Add("Device complies with ACS-2 ANSI INCITS 482-2013"); + + break; + case 0x1765: + scsiOneValue.Add("Device complies with ACS-3 (no version claimed)"); + + break; + case 0x1780: + scsiOneValue.Add("Device complies with UAS-2 (no version claimed)"); + + break; + case 0x1EA0: + scsiOneValue.Add("Device complies with SAT (no version claimed)"); + + break; + case 0x1EA7: + scsiOneValue.Add("Device complies with SAT T10/1711-D revision 8"); + + break; + case 0x1EAB: + scsiOneValue.Add("Device complies with SAT T10/1711-D revision 9"); + + break; + case 0x1EAD: + scsiOneValue.Add("Device complies with SAT ANSI INCITS 431-2007"); + + break; + case 0x1EC0: + scsiOneValue.Add("Device complies with SAT-2 (no version claimed)"); + + break; + case 0x1EC4: + scsiOneValue.Add("Device complies with SAT-2 T10/1826-D revision 06"); + + break; + case 0x1EC8: + scsiOneValue.Add("Device complies with SAT-2 T10/1826-D revision 09"); + + break; + case 0x1ECA: + scsiOneValue.Add("Device complies with SAT-2 ANSI INCITS 465-2010"); + + break; + case 0x1EE0: + scsiOneValue.Add("Device complies with SAT-3 (no version claimed)"); + + break; + case 0x1EE2: + scsiOneValue.Add("Device complies with SAT-3 T10/BSR INCITS 517 revision 4"); + + break; + case 0x1EE4: + scsiOneValue.Add("Device complies with SAT-3 T10/BSR INCITS 517 revision 7"); + + break; + case 0x1EE8: + scsiOneValue.Add("Device complies with SAT-3 ANSI INCITS 517-2015"); + + break; + case 0x1F00: + scsiOneValue.Add("Device complies with SAT-4 (no version claimed)"); + + break; + case 0x20A0: + scsiOneValue.Add("Device complies with SPL (no version claimed)"); + + break; + case 0x20A3: + scsiOneValue.Add("Device complies with SPL T10/2124-D revision 6a"); + + break; + case 0x20A5: + scsiOneValue.Add("Device complies with SPL T10/2124-D revision 7"); + + break; + case 0x20A7: + scsiOneValue.Add("Device complies with SPL ANSI INCITS 476-2011"); + + break; + case 0x20A8: + scsiOneValue.Add("Device complies with SPL ANSI INCITS 476-2011 + SPL AM1 INCITS 476/AM1 2012"); + + break; + case 0x20AA: + scsiOneValue.Add("Device complies with SPL ISO/IEC 14776-261:2012"); + + break; + case 0x20C0: + scsiOneValue.Add("Device complies with SPL-2 (no version claimed)"); + + break; + case 0x20C2: + scsiOneValue.Add("Device complies with SPL-2 T10/BSR INCITS 505 revision 4"); + + break; + case 0x20C4: + scsiOneValue.Add("Device complies with SPL-2 T10/BSR INCITS 505 revision 5"); + + break; + case 0x20C8: + scsiOneValue.Add("Device complies with SPL-2 ANSI INCITS 505-2013"); + + break; + case 0x20E0: + scsiOneValue.Add("Device complies with SPL-3 (no version claimed)"); + + break; + case 0x20E4: + scsiOneValue.Add("Device complies with SPL-3 T10/BSR INCITS 492 revision 6"); + + break; + case 0x20E6: + scsiOneValue.Add("Device complies with SPL-3 T10/BSR INCITS 492 revision 7"); + + break; + case 0x20E8: + scsiOneValue.Add("Device complies with SPL-3 ANSI INCITS 492-2015"); + + break; + case 0x2100: + scsiOneValue.Add("Device complies with SPL-4 (no version claimed)"); + + break; + case 0x21E0: + scsiOneValue.Add("Device complies with SOP (no version claimed)"); + + break; + case 0x21E4: + scsiOneValue.Add("Device complies with SOP T10/BSR INCITS 489 revision 4"); + + break; + case 0x21E6: + scsiOneValue.Add("Device complies with SOP T10/BSR INCITS 489 revision 5"); + + break; + case 0x21E8: + scsiOneValue.Add("Device complies with SOP ANSI INCITS 489-2014"); + + break; + case 0x2200: + scsiOneValue.Add("Device complies with PQI (no version claimed)"); + + break; + case 0x2204: + scsiOneValue.Add("Device complies with PQI T10/BSR INCITS 490 revision 6"); + + break; + case 0x2206: + scsiOneValue.Add("Device complies with PQI T10/BSR INCITS 490 revision 7"); + + break; + case 0x2208: + scsiOneValue.Add("Device complies with PQI ANSI INCITS 490-2014"); + + break; + case 0x2220: + scsiOneValue.Add("Device complies with SOP-2 (no version claimed)"); + + break; + case 0x2240: + scsiOneValue.Add("Device complies with PQI-2 (no version claimed)"); + + break; + case 0xFFC0: + scsiOneValue.Add("Device complies with IEEE 1667 (no version claimed)"); + + break; + case 0xFFC1: + scsiOneValue.Add("Device complies with IEEE 1667-2006"); + + break; + case 0xFFC2: + scsiOneValue.Add("Device complies with IEEE 1667-2009"); + + break; + default: + scsiOneValue.Add($"Device complies with unknown standard code 0x{versionDescriptor:X4}"); + + break; + } + } + + return scsiOneValue; + } +} \ No newline at end of file diff --git a/Aaru.Server.New/Core/ScsiMmcFeatures.cs b/Aaru.Server.New/Core/ScsiMmcFeatures.cs new file mode 100644 index 00000000..3d472858 --- /dev/null +++ b/Aaru.Server.New/Core/ScsiMmcFeatures.cs @@ -0,0 +1,450 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : ScsiMmcFeatures.cs +// Author(s) : Natalia Portillo +// +// Component : Aaru Server. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SCSI MMC features 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.SCSI; + +namespace Aaru.Server.New.Core; + +public static class ScsiMmcFeatures +{ + /// + /// Takes the MMC FEATURES part of a device report and prints it as a list of values to be sequenced by ASP.NET in + /// the rendering + /// + /// FEATURES part of the report + /// List to put the values on + public static void Report(MmcFeatures ftr, out List mmcOneValue) + { + mmcOneValue = []; + + switch(ftr.SupportsAACS) + { + case true when ftr.AACSVersion.HasValue: + mmcOneValue.Add($"Drive supports AACS version {ftr.AACSVersion}"); + + break; + case true: + mmcOneValue.Add("Drive supports AACS"); + + break; + } + + if(ftr.AGIDs.HasValue) mmcOneValue.Add($"Drive supports {ftr.AGIDs} AGIDs concurrently"); + + if(ftr.CanGenerateBindingNonce) + { + mmcOneValue.Add("Drive supports generating the binding nonce"); + + if(ftr.BindingNonceBlocks.HasValue) + mmcOneValue.Add($"{ftr.BindingNonceBlocks} media blocks are required for the binding nonce"); + } + + if(ftr.BlocksPerReadableUnit > 1) + mmcOneValue.Add($"{ftr.BlocksPerReadableUnit} logical blocks per media writable unit"); + + if(ftr.BufferUnderrunFreeInDVD) mmcOneValue.Add("Drive supports zero loss linking writing DVDs"); + + if(ftr.BufferUnderrunFreeInSAO) mmcOneValue.Add("Drive supports zero loss linking in Session at Once Mode"); + + if(ftr.BufferUnderrunFreeInTAO) mmcOneValue.Add("Drive supports zero loss linking in Track at Once Mode"); + + if(ftr.CanAudioScan) mmcOneValue.Add("Drive supports the SCAN command"); + + if(ftr.CanEject) mmcOneValue.Add("Drive can eject media"); + + if(ftr.CanEraseSector) mmcOneValue.Add("Drive supports media that require erasing before writing"); + + if(ftr.CanExpandBDRESpareArea) mmcOneValue.Add("Drive can expand the spare area on a formatted BD-RE disc"); + + if(ftr.CanFormat) mmcOneValue.Add("Drive can format media into logical blocks"); + + if(ftr.CanFormatBDREWithoutSpare) mmcOneValue.Add("Drive can format BD-RE with no spares allocated"); + + if(ftr.CanFormatQCert) mmcOneValue.Add("Drive can format BD-RE discs with quick certification"); + + if(ftr.CanFormatCert) mmcOneValue.Add("Drive can format BD-RE discs with full certification"); + + if(ftr.CanFormatFRF) mmcOneValue.Add("Drive can fast re-format BD-RE discs"); + + if(ftr.CanFormatRRM) mmcOneValue.Add("Drive can format BD-R discs with RRM format"); + + if(ftr.CanLoad) mmcOneValue.Add("Drive can load media"); + + if(ftr.CanMuteSeparateChannels) mmcOneValue.Add("Drive is able to mute channels separately"); + + if(ftr.CanOverwriteSAOTrack) mmcOneValue.Add("Drive can overwrite a SAO track with another in CD-RWs"); + + if(ftr.CanOverwriteTAOTrack) mmcOneValue.Add("Drive can overwrite a TAO track with another in CD-RWs"); + + if(ftr.CanPlayCDAudio) mmcOneValue.Add("Drive has an analogue audio output"); + + if(ftr.CanPseudoOverwriteBDR) mmcOneValue.Add("Drive can write BD-R on Pseudo-OverWrite SRM mode"); + + if(ftr.CanReadAllDualR) mmcOneValue.Add("Drive can read DVD-R DL from all recording modes"); + + if(ftr.CanReadAllDualRW) mmcOneValue.Add("Drive can read DVD-RW DL from all recording modes"); + + if(ftr.CanReadBD) mmcOneValue.Add("Drive can read BD-ROM"); + + if(ftr.CanReadBDR) mmcOneValue.Add("Drive can read BD-R Ver.1"); + + if(ftr.CanReadBDRE1) mmcOneValue.Add("Drive can read BD-RE Ver.1"); + + if(ftr.CanReadBDRE2) mmcOneValue.Add("Drive can read BD-RE Ver.2"); + + if(ftr.CanReadBDROM) mmcOneValue.Add("Drive can read BD-ROM Ver.1"); + + if(ftr.CanReadBluBCA) mmcOneValue.Add("Drive can read BD's Burst Cutting Area"); + + if(ftr.CanReadCD) mmcOneValue.Add("Drive can read CD-ROM"); + + switch(ftr) + { + case { CanWriteCDMRW: true, CanReadDVDPlusMRW: true, CanWriteDVDPlusMRW: true }: + mmcOneValue.Add("Drive can read and write CD-MRW and DVD+MRW"); + + break; + case { CanReadDVDPlusMRW: true, CanWriteDVDPlusMRW: true }: + mmcOneValue.Add("Drive can read and write DVD+MRW"); + + break; + case { CanWriteCDMRW: true, CanReadDVDPlusMRW: true }: + mmcOneValue.Add("Drive and read DVD+MRW and read and write CD-MRW"); + + break; + default: + { + if(ftr.CanWriteCDMRW) + mmcOneValue.Add("Drive can read and write CD-MRW"); + else if(ftr.CanReadDVDPlusMRW) + mmcOneValue.Add("Drive can read CD-MRW and DVD+MRW"); + else if(ftr.CanReadCDMRW) mmcOneValue.Add("Drive can read CD-MRW"); + + break; + } + } + + if(ftr.CanReadCPRM_MKB) mmcOneValue.Add("Drive supports reading Media Key Block of CPRM"); + + if(ftr.CanReadDDCD) mmcOneValue.Add("Drive can read DDCDs"); + + if(ftr.CanReadDVD) mmcOneValue.Add("Drive can read DVD"); + + if(ftr.CanWriteDVDPlusRW) + mmcOneValue.Add("Drive can read and write DVD+RW"); + else if(ftr.CanReadDVDPlusRW) mmcOneValue.Add("Drive can read DVD+RW"); + + if(ftr.CanWriteDVDPlusR) + mmcOneValue.Add("Drive can read and write DVD+R"); + else if(ftr.CanReadDVDPlusR) mmcOneValue.Add("Drive can read DVD+R"); + + if(ftr.CanWriteDVDPlusRDL) + mmcOneValue.Add("Drive can read and write DVD+R DL"); + else if(ftr.CanReadDVDPlusRDL) mmcOneValue.Add("Drive can read DVD+R DL"); + + if(ftr.CanReadDriveAACSCertificate) mmcOneValue.Add("Drive supports reading the Drive Certificate"); + + switch(ftr) + { + case { CanReadHDDVD: true, CanReadHDDVDR: true, CanReadHDDVDRAM: true }: + mmcOneValue.Add("Drive can read HD DVD-ROM, HD DVD-RW, HD DVD-R and HD DVD-RAM"); + + break; + case { CanReadHDDVD: true, CanReadHDDVDR: true }: + mmcOneValue.Add("Drive can read HD DVD-ROM, HD DVD-RW and HD DVD-R"); + + break; + case { CanReadHDDVD: true, CanReadHDDVDRAM: true }: + mmcOneValue.Add("Drive can read HD DVD-ROM, HD DVD-RW and HD DVD-RAM"); + + break; + default: + { + if(ftr.CanReadHDDVD) mmcOneValue.Add("Drive can read HD DVD-ROM and HD DVD-RW"); + + break; + } + } + + if(ftr.CanReadLeadInCDText) mmcOneValue.Add("Drive can return CD-Text from Lead-In"); + + if(ftr.CanReadOldBDR) mmcOneValue.Add("Drive can read BD-R pre-1.0"); + + if(ftr.CanReadOldBDRE) mmcOneValue.Add("Drive can read BD-RE pre-1.0"); + + if(ftr.CanReadOldBDROM) mmcOneValue.Add("Drive can read BD-ROM pre-1.0"); + + if(ftr.CanReadSpareAreaInformation) mmcOneValue.Add("Drive can return Spare Area Information"); + + if(ftr.CanReportDriveSerial) mmcOneValue.Add("Drive is to report drive serial number"); + + if(ftr.CanReportMediaSerial) mmcOneValue.Add("Drive is to read media serial number"); + + if(ftr.CanTestWriteDDCDR) mmcOneValue.Add("Drive can do a test writing with DDCD-R"); + + if(ftr.CanTestWriteDVD) mmcOneValue.Add("Drive can do a test writing with DVDs"); + + if(ftr.CanTestWriteInSAO) mmcOneValue.Add("Drive can do a test writing in Session at Once Mode"); + + if(ftr.CanTestWriteInTAO) mmcOneValue.Add("Drive can do a test writing in Track at Once Mode"); + + if(ftr.CanUpgradeFirmware) mmcOneValue.Add("Drive supports Microcode Upgrade"); + + if(ftr.ErrorRecoveryPage) mmcOneValue.Add("Drive shall report Read/Write Error Recovery mode page"); + + if(ftr.Locked) mmcOneValue.Add("Drive can lock media"); + + if(ftr.LogicalBlockSize > 0) mmcOneValue.Add($"{ftr.LogicalBlockSize} bytes per logical block"); + + if(ftr.MultiRead) + mmcOneValue.Add("Drive claims capability to read all CD formats according to OSTA Multi-Read Specification"); + + if(ftr.PhysicalInterfaceStandard.HasValue) + { + switch(ftr.PhysicalInterfaceStandard) + { + case PhysicalInterfaces.Unspecified: + mmcOneValue.Add("Drive uses an unspecified physical interface"); + + break; + case PhysicalInterfaces.SCSI: + mmcOneValue.Add("Drive uses SCSI interface"); + + break; + case PhysicalInterfaces.ATAPI: + mmcOneValue.Add("Drive uses ATAPI interface"); + + break; + case PhysicalInterfaces.IEEE1394: + mmcOneValue.Add("Drive uses IEEE-1394 interface"); + + break; + case PhysicalInterfaces.IEEE1394A: + mmcOneValue.Add("Drive uses IEEE-1394A interface"); + + break; + case PhysicalInterfaces.FC: + mmcOneValue.Add("Drive uses Fibre Channel interface"); + + break; + case PhysicalInterfaces.IEEE1394B: + mmcOneValue.Add("Drive uses IEEE-1394B interface"); + + break; + case PhysicalInterfaces.SerialATAPI: + mmcOneValue.Add("Drive uses Serial ATAPI interface"); + + break; + case PhysicalInterfaces.USB: + mmcOneValue.Add("Drive uses USB interface"); + + break; + case PhysicalInterfaces.Vendor: + mmcOneValue.Add("Drive uses a vendor unique interface"); + + break; + default: + mmcOneValue.Add($"Drive uses an unknown interface with code {(uint)ftr.PhysicalInterfaceStandard}"); + + break; + } + } + + if(ftr.PreventJumper) mmcOneValue.Add("Drive power ups locked"); + + if(ftr.SupportsBusEncryption) mmcOneValue.Add("Drive supports bus encryption"); + + if(ftr.CanWriteBD) mmcOneValue.Add("Drive can write BD-R or BD-RE"); + + if(ftr.CanWriteBDR) mmcOneValue.Add("Drive can write BD-R Ver.1"); + + if(ftr.CanWriteBDRE1) mmcOneValue.Add("Drive can write BD-RE Ver.1"); + + if(ftr.CanWriteBDRE2) mmcOneValue.Add("Drive can write BD-RE Ver.2"); + + if(ftr.CanWriteBusEncryptedBlocks) mmcOneValue.Add("Drive supports writing with bus encryption"); + + if(ftr.CanWriteCDRW) mmcOneValue.Add("Drive can write CD-RW"); + + if(ftr.CanWriteCDRWCAV) mmcOneValue.Add("Drive can write High-Speed CD-RW"); + + if(ftr.CanWriteCDSAO && !ftr.CanWriteRaw) + mmcOneValue.Add("Drive can write CDs in Session at Once Mode:"); + else if(!ftr.CanWriteCDSAO && ftr.CanWriteRaw) + mmcOneValue.Add("Drive can write CDs in raw Mode:"); + else if(ftr.CanWriteCDSAO && ftr.CanWriteRaw) + mmcOneValue.Add("Drive can write CDs in Session at Once and in Raw Modes:"); + + if(ftr.CanWriteCDTAO) mmcOneValue.Add("Drive can write CDs in Track at Once Mode:"); + + if(ftr.CanWriteCSSManagedDVD) mmcOneValue.Add("Drive can write CSS managed DVDs"); + + if(ftr.CanWriteDDCDR) mmcOneValue.Add("Drive supports writing DDCD-R"); + + if(ftr.CanWriteDDCDRW) mmcOneValue.Add("Drive supports writing DDCD-RW"); + + if(ftr.CanWriteDVDPlusRWDL) + mmcOneValue.Add("Drive can read and write DVD+RW DL"); + else if(ftr.CanReadDVDPlusRWDL) mmcOneValue.Add("Drive can read DVD+RW DL"); + + if(ftr.CanWriteDVDR && ftr.CanWriteDVDRW && ftr.CanWriteDVDRDL) + mmcOneValue.Add("Drive supports writing DVD-R, DVD-RW and DVD-R DL"); + else if(ftr.CanWriteDVDR && ftr.CanWriteDVDRDL) + mmcOneValue.Add("Drive supports writing DVD-R and DVD-R DL"); + else if(ftr.CanWriteDVDR && ftr.CanWriteDVDRW) + mmcOneValue.Add("Drive supports writing DVD-R and DVD-RW"); + else if(ftr.CanWriteDVDR) mmcOneValue.Add("Drive supports writing DVD-R"); + + if(ftr.CanWriteHDDVDR && ftr.CanWriteHDDVDRAM) + mmcOneValue.Add("Drive can write HD DVD-RW, HD DVD-R and HD DVD-RAM"); + else if(ftr.CanWriteHDDVDR) + mmcOneValue.Add("Drive can write HD DVD-RW and HD DVD-R"); + else if(ftr.CanWriteHDDVDRAM) mmcOneValue.Add("Drive can write HD DVD-RW and HD DVD-RAM"); + + // TODO: Write HD DVD-RW + /* + else + mmcOneValue.Add("Drive can write HD DVD-RW"); + */ + if(ftr.CanWriteOldBDR) mmcOneValue.Add("Drive can write BD-R pre-1.0"); + + if(ftr.CanWriteOldBDRE) mmcOneValue.Add("Drive can write BD-RE pre-1.0"); + + if(ftr.CanWriteRWSubchannelInTAO) + { + mmcOneValue.Add("Drive can write user provided data in the R-W subchannels in Track at Once Mode"); + + if(ftr.CanWriteRawSubchannelInTAO) + mmcOneValue.Add("Drive accepts RAW R-W subchannel data in Track at Once Mode"); + + if(ftr.CanWritePackedSubchannelInTAO) + mmcOneValue.Add("Drive accepts Packed R-W subchannel data in Track at Once Mode"); + } + + if(ftr.CanWriteRWSubchannelInSAO) + mmcOneValue.Add("Drive can write user provided data in the R-W subchannels in Session at Once Mode"); + + if(ftr.CanWriteRaw && ftr.CanWriteRawMultiSession) + mmcOneValue.Add("Drive can write multi-session CDs in raw mode"); + + if(ftr.EmbeddedChanger) + { + mmcOneValue.Add("Drive contains an embedded changer"); + + if(ftr.ChangerIsSideChangeCapable) mmcOneValue.Add("Drive can change disc side"); + + if(ftr.ChangerSupportsDiscPresent) + mmcOneValue.Add("Drive is able to report slots contents after a reset or change"); + + mmcOneValue.Add($"Drive has {ftr.ChangerSlots + 1} slots"); + } + + if(ftr.SupportsCSS && ftr.CSSVersion.HasValue) + mmcOneValue.Add($"Drive supports DVD CSS/CPPM version {ftr.CSSVersion}"); + else if(ftr.SupportsCSS) mmcOneValue.Add("Drive supports DVD CSS/CPRM"); + + if(ftr.SupportsCPRM && ftr.CPRMVersion.HasValue) + mmcOneValue.Add($"Drive supports DVD CPRM version {ftr.CPRMVersion}"); + else if(ftr.SupportsCPRM) mmcOneValue.Add("Drive supports DVD CPRM"); + + if(ftr.DBML) mmcOneValue.Add("Drive reports Device Busy Class events during medium loading/unloading"); + + if(ftr.DVDMultiRead) mmcOneValue.Add("Drive conforms to DVD Multi Drive Read-only Specifications"); + + if(ftr.FirmwareDate.HasValue) mmcOneValue.Add($"Drive firmware is dated {ftr.FirmwareDate}"); + + if(ftr.SupportsC2) mmcOneValue.Add("Drive supports C2 Error Pointers"); + + if(ftr.SupportsDAP) mmcOneValue.Add("Drive supports the DAP bit in the READ CD and READ CD MSF commands"); + + if(ftr.SupportsDeviceBusyEvent) mmcOneValue.Add("Drive supports Device Busy events"); + + if(ftr.LoadingMechanismType.HasValue) + { + switch(ftr.LoadingMechanismType) + { + case 0: + mmcOneValue.Add("Drive uses media caddy"); + + break; + case 1: + mmcOneValue.Add("Drive uses a tray"); + + break; + case 2: + mmcOneValue.Add("Drive is pop-up"); + + break; + case 4: + mmcOneValue.Add("Drive is a changer with individually changeable discs"); + + break; + case 5: + mmcOneValue.Add("Drive is a changer using cartridges"); + + break; + default: + mmcOneValue.Add($"Drive uses unknown loading mechanism type {ftr.LoadingMechanismType}"); + + break; + } + } + + if(ftr.SupportsHybridDiscs) mmcOneValue.Add("Drive is able to access Hybrid discs"); + + if(ftr.SupportsModePage1Ch) + mmcOneValue.Add("Drive supports the Informational Exceptions Control mode page 1Ch"); + + if(ftr.SupportsOSSC) + mmcOneValue.Add("Drive supports the Trusted Computing Group Optical Security Subsystem Class"); + + if(ftr.SupportsPWP) mmcOneValue.Add("Drive supports set/release of PWP status"); + + if(ftr.SupportsSWPP) mmcOneValue.Add("Drive supports the SWPP bit of the Timeout and Protect mode page"); + + if(ftr.SupportsSecurDisc) mmcOneValue.Add("Drive supports SecurDisc"); + + if(ftr.SupportsSeparateVolume) mmcOneValue.Add("Drive supports separate volume per channel"); + + if(ftr.SupportsVCPS) mmcOneValue.Add("Drive supports VCPS"); + + if(ftr.VolumeLevels.HasValue) mmcOneValue.Add($"Drive has {ftr.VolumeLevels + 1} volume levels"); + + if(ftr.SupportsWriteProtectPAC) + mmcOneValue.Add("Drive supports reading/writing the Disc Write Protect PAC on BD-R/-RE media"); + + if(ftr.SupportsWriteInhibitDCB) mmcOneValue.Add("Drive supports writing the Write Inhibit DCB on DVD+RW media"); + + mmcOneValue.Sort(); + } +} \ No newline at end of file diff --git a/Aaru.Server.New/Core/ScsiMmcMode.cs b/Aaru.Server.New/Core/ScsiMmcMode.cs new file mode 100644 index 00000000..7da14ded --- /dev/null +++ b/Aaru.Server.New/Core/ScsiMmcMode.cs @@ -0,0 +1,214 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : ScsiMmcMode.cs +// Author(s) : Natalia Portillo +// +// Component : Aaru Server. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SCSI MODE PAGE 2Ah 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.Structs.Devices.SCSI.Modes; + +namespace Aaru.Server.New.Core; + +public static class ScsiMmcMode +{ + /// + /// Takes the MODE PAGE 2Ah part of a device report and prints it as a list of values to be sequenced by ASP.NET + /// in the rendering + /// + /// MODE PAGE 2Ah part of the report + /// List to put the values on + public static void Report(ModePage_2A mode, out List mmcOneValue) + { + mmcOneValue = []; + + if(mode.AudioPlay) mmcOneValue.Add("Drive can play audio"); + + if(mode.Mode2Form1) mmcOneValue.Add("Drive can read sectors in Mode 2 Form 1 format"); + + if(mode.Mode2Form2) mmcOneValue.Add("Drive can read sectors in Mode 2 Form 2 format"); + + if(mode.MultiSession) mmcOneValue.Add("Drive supports multi-session discs and/or Photo-CD"); + + if(mode.CDDACommand) mmcOneValue.Add("Drive can read digital audio"); + + if(mode.AccurateCDDA) mmcOneValue.Add("Drive can continue from streaming loss"); + + if(mode.Subchannel) mmcOneValue.Add("Drive can read uncorrected and interleaved R-W subchannels"); + + if(mode.DeinterlaveSubchannel) mmcOneValue.Add("Drive can read, deinterleave and correct R-W subchannels"); + + if(mode.C2Pointer) mmcOneValue.Add("Drive supports C2 pointers"); + + if(mode.UPC) mmcOneValue.Add("Drive can read Media Catalogue Number"); + + if(mode.ISRC) mmcOneValue.Add("Drive can read ISRC"); + + switch(mode.LoadingMechanism) + { + case 0: + mmcOneValue.Add("Drive uses media caddy"); + + break; + case 1: + mmcOneValue.Add("Drive uses a tray"); + + break; + case 2: + mmcOneValue.Add("Drive is pop-up"); + + break; + case 4: + mmcOneValue.Add("Drive is a changer with individually changeable discs"); + + break; + case 5: + mmcOneValue.Add("Drive is a changer using cartridges"); + + break; + default: + mmcOneValue.Add($"Drive uses unknown loading mechanism type {mode.LoadingMechanism}"); + + break; + } + + if(mode.Lock) mmcOneValue.Add("Drive can lock media"); + + if(mode.PreventJumper) + { + mmcOneValue.Add("Drive power ups locked"); + + mmcOneValue.Add(mode.LockState + ? "Drive is locked, media cannot be ejected or inserted" + : "Drive is not locked, media can be ejected and inserted"); + } + else + { + mmcOneValue.Add(mode.LockState + ? "Drive is locked, media cannot be ejected, but if empty, can be inserted" + : "Drive is not locked, media can be ejected and inserted"); + } + + if(mode.Eject) mmcOneValue.Add("Drive can eject media"); + + if(mode.SeparateChannelMute) mmcOneValue.Add("Each channel can be muted independently"); + + if(mode.SeparateChannelVolume) mmcOneValue.Add("Each channel's volume can be controlled independently"); + + if(mode.SupportedVolumeLevels > 0) + mmcOneValue.Add($"Drive supports {mode.SupportedVolumeLevels} volume levels"); + + if(mode.BufferSize > 0) mmcOneValue.Add($"Drive has {mode.BufferSize} Kbyte of buffer"); + + if(mode.MaximumSpeed > 0) mmcOneValue.Add($"Drive's maximum reading speed is {mode.MaximumSpeed} Kbyte/sec."); + + if(mode.CurrentSpeed > 0) mmcOneValue.Add($"Drive's current reading speed is {mode.CurrentSpeed} Kbyte/sec."); + + if(mode.ReadCDR) + { + mmcOneValue.Add(mode.WriteCDR ? "Drive can read and write CD-R" : "Drive can read CD-R"); + + if(mode.Method2) mmcOneValue.Add("Drive supports reading CD-R packet media"); + } + + if(mode.ReadCDRW) mmcOneValue.Add(mode.WriteCDRW ? "Drive can read and write CD-RW" : "Drive can read CD-RW"); + + if(mode.ReadDVDROM) mmcOneValue.Add("Drive can read DVD-ROM"); + + if(mode.ReadDVDR) mmcOneValue.Add(mode.WriteDVDR ? "Drive can read and write DVD-R" : "Drive can read DVD-R"); + + if(mode.ReadDVDRAM) + mmcOneValue.Add(mode.WriteDVDRAM ? "Drive can read and write DVD-RAM" : "Drive can read DVD-RAM"); + + if(mode.Composite) mmcOneValue.Add("Drive can deliver a composite audio and video data stream"); + + if(mode.DigitalPort1) mmcOneValue.Add("Drive supports IEC-958 digital output on port 1"); + + if(mode.DigitalPort2) mmcOneValue.Add("Drive supports IEC-958 digital output on port 2"); + + if(mode.SDP) mmcOneValue.Add("Drive contains a changer that can report the exact contents of the slots"); + + if(mode.CurrentWriteSpeedSelected > 0) + { + switch(mode.RotationControlSelected) + { + case 0: + mmcOneValue + .Add($"Drive's current writing speed is {mode.CurrentWriteSpeedSelected} Kbyte/sec. in CLV mode"); + + break; + case 1: + mmcOneValue + .Add($"Drive's current writing speed is {mode.CurrentWriteSpeedSelected} Kbyte/sec. in pure CAV mode"); + + break; + } + } + else + { + if(mode.MaxWriteSpeed > 0) + mmcOneValue.Add($"Drive's maximum writing speed is {mode.MaxWriteSpeed} Kbyte/sec."); + + if(mode.CurrentWriteSpeed > 0) + mmcOneValue.Add($"Drive's current writing speed is {mode.CurrentWriteSpeed} Kbyte/sec."); + } + + if(mode.WriteSpeedPerformanceDescriptors != null) + { + foreach(ModePage_2A_WriteDescriptor descriptor in + mode.WriteSpeedPerformanceDescriptors.Where(static descriptor => descriptor.WriteSpeed > 0)) + { + switch(descriptor.RotationControl) + { + case 0: + mmcOneValue.Add($"Drive supports writing at {descriptor.WriteSpeed} Kbyte/sec. in CLV mode"); + + break; + case 1: + mmcOneValue + .Add($"Drive supports writing at is {descriptor.WriteSpeed} Kbyte/sec. in pure CAV mode"); + + break; + } + } + } + + if(mode.TestWrite) mmcOneValue.Add("Drive supports test writing"); + + if(mode.ReadBarcode) mmcOneValue.Add("Drive can read barcode"); + + if(mode.SCC) mmcOneValue.Add("Drive can read both sides of a disc"); + + if(mode.LeadInPW) mmcOneValue.Add("Drive an read raw R-W subchannel from the Lead-In"); + + if(mode.CMRSupported == 1) mmcOneValue.Add("Drive supports DVD CSS and/or DVD CPPM"); + + if(mode.BUF) mmcOneValue.Add("Drive supports buffer under-run free recording"); + + mmcOneValue.Sort(); + } +} \ No newline at end of file diff --git a/Aaru.Server.New/Core/ScsiModeSense.cs b/Aaru.Server.New/Core/ScsiModeSense.cs new file mode 100644 index 00000000..05e33635 --- /dev/null +++ b/Aaru.Server.New/Core/ScsiModeSense.cs @@ -0,0 +1,980 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : ScsiModeSense.cs +// Author(s) : Natalia Portillo +// +// Component : Aaru Server. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SCSI MODE PAGEs 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.SCSI; +using Aaru.Decoders.SCSI; + +namespace Aaru.Server.New.Core; + +public static class ScsiModeSense +{ + /// + /// Takes the MODE PAGEs 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 + /// + /// MODE PAGEs part of a device report + /// SCSI vendor string + /// SCSI peripheral device type + /// List to put values on + /// List to put key=value pairs on + public static void Report(ScsiMode modeSense, string vendor, PeripheralDeviceTypes deviceType, + out List? modeSenseCapabilities, out List? blockDescriptors, + out Dictionary> modePages) + { + modeSenseCapabilities = null; + blockDescriptors = null; + modePages = new Dictionary>(); + + if(modeSense.MediumType.HasValue) + { + modeSenseCapabilities ??= []; + modeSenseCapabilities.Add($"Medium type is {modeSense.MediumType:X2}h"); + } + + if(modeSense.WriteProtected) + { + modeSenseCapabilities ??= []; + modeSenseCapabilities.Add("Device is write protected."); + } + + if(modeSense.BlockDescriptors?.Count > 0) + { + blockDescriptors ??= []; + + foreach(BlockDescriptor descriptor in modeSense.BlockDescriptors) + { + if(descriptor.Blocks.HasValue && descriptor.BlockLength.HasValue) + { + blockDescriptors + .Add($"Density code {descriptor.Density:X2}h has {descriptor.Blocks} blocks of {descriptor.BlockLength} bytes each"); + } + else + blockDescriptors.Add($"Density code {descriptor.Density:X2}h"); + } + } + + if(modeSense.DPOandFUA) + { + modeSenseCapabilities ??= []; + modeSenseCapabilities.Add("Drive supports DPO and FUA bits"); + } + + if(modeSense.BlankCheckEnabled) + { + modeSenseCapabilities ??= []; + modeSenseCapabilities.Add("Blank checking during write is enabled"); + } + + if(modeSense.BufferedMode.HasValue) + { + modeSenseCapabilities ??= []; + + switch(modeSense.BufferedMode) + { + case 0: + modeSenseCapabilities.Add("Device writes directly to media"); + + break; + case 1: + modeSenseCapabilities.Add("Device uses a write cache"); + + break; + case 2: + modeSenseCapabilities.Add("Device uses a write cache but doesn't return until cache is flushed"); + + break; + default: + modeSenseCapabilities.Add($"Unknown buffered mode code 0x{modeSense.BufferedMode:X2}"); + + break; + } + } + + if(modeSense.ModePages == null) return; + + foreach(ScsiPage page in modeSense.ModePages) + { + switch(page.page) + { + case 0x00: + { + if(deviceType == PeripheralDeviceTypes.MultiMediaDevice && page.subpage == 0) + { + string pretty = Modes.PrettifyModePage_00_SFF(page.value); + + if(pretty is not null) + { + modePages.Add($"MODE page {page.page:X2}h", + pretty.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | + StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList()); + } + else + goto default; + } + else + { + modePages.Add(page.subpage != 0 + ? $"MODE page {page.page:X2}h subpage {page.subpage:X2}h" + : $"MODE page {page.page:X2}h", + ["Unknown vendor mode page"]); + } + + break; + } + case 0x01: + { + if(page.subpage == 0) + { + string pretty = deviceType == PeripheralDeviceTypes.MultiMediaDevice + ? Modes.PrettifyModePage_01_MMC(page.value) + : Modes.PrettifyModePage_01(page.value); + + if(pretty is not null) + { + modePages.Add(deviceType == PeripheralDeviceTypes.MultiMediaDevice + ? "MODE page 01h: Read error recovery page for MultiMedia Devices" + : "MODE page 01h: Read-write error recovery page", + pretty.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | + StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList()); + } + else + goto default; + } + else + goto default; + + break; + } + case 0x02: + { + if(page.subpage == 0) + { + string pretty = Modes.PrettifyModePage_02(page.value); + + if(pretty is not null) + + { + modePages.Add("MODE page 02h: Disconnect-Reconnect page", + pretty.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | + StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList()); + } + else + goto default; + } + else + goto default; + + break; + } + case 0x03: + { + if(page.subpage == 0) + { + string pretty = Modes.PrettifyModePage_03(page.value); + + if(pretty is not null) + { + modePages.Add("MODE page 03h: Format device page", + pretty.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | + StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList()); + } + else + goto default; + } + else + goto default; + + break; + } + case 0x04: + { + if(page.subpage == 0) + { + string pretty = Modes.PrettifyModePage_04(page.value); + + if(pretty is not null) + { + modePages.Add("MODE page 04h: Rigid disk drive geometry page", + pretty.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | + StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList()); + } + else + goto default; + } + else + goto default; + + break; + } + case 0x05: + { + if(page.subpage == 0) + { + string pretty = Modes.PrettifyModePage_05(page.value); + + if(pretty is not null) + { + modePages.Add("MODE page 05h: Flexible disk page", + pretty.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | + StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList()); + } + else + goto default; + } + else + goto default; + + break; + } + case 0x06: + { + if(page.subpage == 0) + + { + string pretty = Modes.PrettifyModePage_06(page.value); + + if(pretty is not null) + { + modePages.Add("MODE page 06h: Optical memory page", + pretty.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | + StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList()); + } + else + goto default; + } + else + goto default; + + break; + } + case 0x07: + { + if(page.subpage == 0) + { + string pretty = deviceType == PeripheralDeviceTypes.MultiMediaDevice + ? Modes.PrettifyModePage_07_MMC(page.value) + : Modes.PrettifyModePage_07(page.value); + + if(pretty is not null) + { + modePages.Add(deviceType == PeripheralDeviceTypes.MultiMediaDevice + ? "MODE page 07h: Verify error recovery page for MultiMedia Devices" + : "MODE page 07h: Verify error recovery page", + pretty.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | + StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList()); + } + else + goto default; + } + else + goto default; + + break; + } + case 0x08: + { + if(page.subpage == 0) + { + string pretty = Modes.PrettifyModePage_08(page.value); + + if(pretty is not null) + { + modePages.Add($"MODE page {page.page:X2}h", + pretty.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | + StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList()); + } + else + goto default; + } + else + goto default; + + break; + } + case 0x0A: + { + if(page.subpage == 0) + { + string pretty = Modes.PrettifyModePage_0A(page.value); + + if(pretty is not null) + { + modePages.Add("MODE page 0Ah: Control mode page", + pretty.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | + StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList()); + } + else + goto default; + } + else if(page.subpage == 1) + { + string pretty = Modes.PrettifyModePage_0A_S01(page.value); + + if(pretty is not null) + { + modePages.Add("MODE page 0Ah subpage 01h: Control extension page", + pretty.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | + StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList()); + } + else + goto default; + } + else + goto default; + + break; + } + case 0x0B: + { + if(page.subpage == 0) + { + string pretty = Modes.PrettifyModePage_0B(page.value); + + if(pretty is not null) + { + modePages.Add("MODE page 0Bh: Medium types supported page", + pretty.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | + StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList()); + } + else + goto default; + } + else + goto default; + + break; + } + case 0x0D: + { + if(page.subpage == 0) + { + string pretty = Modes.PrettifyModePage_0D(page.value); + + if(pretty is not null) + { + modePages.Add("MODE page 0Dh: CD-ROM parameters page", + pretty.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | + StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList()); + } + else + goto default; + } + else + goto default; + + break; + } + case 0x0E: + { + if(page.subpage == 0) + { + string pretty = Modes.PrettifyModePage_0E(page.value); + + if(pretty is not null) + { + modePages.Add("MODE page 0Eh: CD-ROM audio control parameters page", + pretty.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | + StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList()); + } + else + goto default; + } + else + goto default; + + break; + } + case 0x0F: + { + if(page.subpage == 0) + { + string pretty = Modes.PrettifyModePage_0F(page.value); + + if(pretty is not null) + { + modePages.Add("MODE page 0Fh: Data compression page", + pretty.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | + StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList()); + } + else + goto default; + } + else + goto default; + + break; + } + case 0x10: + { + if(page.subpage == 0) + { + string pretty = deviceType == PeripheralDeviceTypes.SequentialAccess + ? Modes.PrettifyModePage_10_SSC(page.value) + : Modes.PrettifyModePage_10(page.value); + + if(pretty is not null) + { + modePages.Add(deviceType == PeripheralDeviceTypes.SequentialAccess + ? "MODE page 10h: Device configuration page" + : "MODE page 10h: XOR control mode page", + pretty.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | + StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList()); + } + else + goto default; + } + else + goto default; + + break; + } + case 0x11: + { + if(page.subpage == 0) + { + string pretty = Modes.PrettifyModePage_11(page.value); + + if(pretty is not null) + { + modePages.Add("MODE page 11h: Medium partition page", + pretty.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | + StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList()); + } + else + goto default; + } + else + goto default; + + break; + } + case 0x12: + case 0x13: + case 0x14: + { + if(page.subpage == 0) + { + string pretty = Modes.PrettifyModePage_12_13_14(page.value); + + if(pretty is not null) + { + modePages.Add($"MODE page {page.page:X2}h: Medium partition page (extra)", + pretty.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | + StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList()); + } + else + goto default; + } + else + goto default; + + break; + } + case 0x1A: + { + if(page.subpage == 0) + { + string pretty = Modes.PrettifyModePage_1A(page.value); + + if(pretty is not null) + { + modePages.Add("MODE page 1Ah: Power condition page", + pretty.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | + StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList()); + } + else + goto default; + } + else if(page.subpage == 1) + { + string pretty = Modes.PrettifyModePage_1A_S01(page.value); + + if(pretty is not null) + { + modePages.Add("MODE page 1Ah subpage 01h: Power Consumption page", + pretty.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | + StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList()); + } + else + goto default; + } + else + goto default; + + break; + } + case 0x1B: + { + if(page.subpage == 0) + { + string pretty = Modes.PrettifyModePage_1B(page.value); + + if(pretty is not null) + { + modePages.Add("MODE page 1Bh: Removable Block Access Capabilities page", + pretty.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | + StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList()); + } + else + goto default; + } + else + goto default; + + break; + } + case 0x1C: + { + if(page.subpage == 0) + { + string pretty = deviceType == PeripheralDeviceTypes.MultiMediaDevice + ? Modes.PrettifyModePage_1C_SFF(page.value) + : Modes.PrettifyModePage_1C(page.value); + + if(pretty is not null) + { + modePages.Add(deviceType == PeripheralDeviceTypes.MultiMediaDevice + ? "MODE page 1Ch: Timer & Protect page" + : "MODE page 1Ch: Informational exceptions control page", + pretty.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | + StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList()); + } + else + goto default; + } + else if(page.subpage == 1) + { + string pretty = Modes.PrettifyModePage_1C_S01(page.value); + + if(pretty is not null) + { + modePages.Add("MODE page 1Ch subpage 01h: Background Control page", + pretty.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | + StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList()); + } + else + goto default; + } + else + goto default; + + break; + } + case 0x1D: + { + if(page.subpage == 0) + { + string pretty = Modes.PrettifyModePage_1D(page.value); + + if(pretty is not null) + { + modePages.Add("MODE page 1Dh: Medium Configuration page", + pretty.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | + StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList()); + } + else + goto default; + } + else + goto default; + + break; + } + case 0x21: + { + if(vendor == "CERTANCE") + { + string pretty = Modes.PrettifyCertanceModePage_21(page.value); + + if(pretty is not null) + { + modePages.Add("MODE page 21h: Certance Drive Capabilities Control page", + pretty.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | + StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList()); + } + else + goto default; + } + else + goto default; + + break; + } + case 0x22: + { + if(vendor == "CERTANCE") + { + string pretty = Modes.PrettifyCertanceModePage_22(page.value); + + if(pretty is not null) + { + modePages.Add("MODE page 22h: Certance Interface Control page", + pretty.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | + StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList()); + } + else + goto default; + } + else + goto default; + + break; + } + case 0x24: + { + if(vendor == "IBM") + { + string pretty = Modes.PrettifyIBMModePage_24(page.value); + + if(pretty is not null) + { + modePages.Add("MODE page 24h: IBM Vendor-Specific Control page", + pretty.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | + StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList()); + } + else + goto default; + } + else + goto default; + + break; + } + case 0x2A: + { + if(page.subpage == 0) + { + string pretty = Modes.PrettifyModePage_2A(page.value); + + if(pretty is not null) + { + modePages.Add("MODE page 2Ah: CD-ROM capabilities page", + pretty.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | + StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList()); + } + else + goto default; + } + else + goto default; + + break; + } + case 0x2F: + { + if(vendor == "IBM") + { + string pretty = Modes.PrettifyIBMModePage_2F(page.value); + + if(pretty is not null) + { + modePages.Add("MODE page 2Fh: IBM Behaviour Configuration page", + pretty.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | + StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList()); + } + else + goto default; + } + else + goto default; + + break; + } + case 0x30: + { + if(Modes.IsAppleModePage_30(page.value)) + modePages.Add("MODE page 30h", ["Drive identifies as an Apple OEM drive"]); + else + goto default; + + break; + } + case 0x3B: + { + if(vendor == "HP") + { + string pretty = Modes.PrettifyHPModePage_3B(page.value); + + if(pretty is not null) + { + modePages.Add("MODE page 3Bh: HP Serial Number Override page", + pretty.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | + StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList()); + } + else + goto default; + } + else + goto default; + + break; + } + case 0x3C: + { + if(vendor == "HP") + { + string pretty = Modes.PrettifyHPModePage_3C(page.value); + + if(pretty is not null) + { + modePages.Add("MODE page 3Ch: HP Device Time page", + pretty.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | + StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList()); + } + else + goto default; + } + else + goto default; + + break; + } + case 0x3D: + { + if(vendor == "IBM") + { + string pretty = Modes.PrettifyIBMModePage_3D(page.value); + + if(pretty is not null) + { + modePages.Add("MODE page 3Dh: IBM LEOT page", + pretty.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | + StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList()); + } + else + goto default; + } + else if(vendor == "HP") + { + string pretty = Modes.PrettifyHPModePage_3D(page.value); + + if(pretty is not null) + { + modePages.Add("MODE page 3Dh: HP Extended Reset page", + pretty.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | + StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList()); + } + else + goto default; + } + else + goto default; + + break; + } + case 0x3E: + { + if(vendor == "FUJITSU") + { + string pretty = Modes.PrettifyFujitsuModePage_3E(page.value); + + if(pretty is not null) + { + modePages.Add("MODE page 3Eh: Fujitsu Verify Control page", + pretty.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | + StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList()); + } + else + goto default; + } + else if(vendor == "HP") + { + string pretty = Modes.PrettifyHPModePage_3E(page.value); + + if(pretty is not null) + { + modePages.Add("MODE page 3Eh: HP CD-ROM Emulation/Disaster Recovery page", + pretty.Replace("\t", "") + .Split(Environment.NewLine, + StringSplitOptions.TrimEntries | + StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToList()); + } + else + goto default; + } + else + goto default; + + break; + } + default: + { + modePages.Add(page.subpage != 0 + ? $"MODE page {page.page:X2}h subpage {page.subpage:X2}h: Unknown page" + : $"MODE page {page.page:X2}h: Unknown page", + []); + } + + break; + } + } + } +} \ No newline at end of file