mirror of
https://github.com/aaru-dps/Aaru.Server.git
synced 2025-12-16 19:24:27 +00:00
Add SCSI to device report view.
This commit is contained in:
294
Aaru.Server.New/Core/ScsiEvpd.cs
Normal file
294
Aaru.Server.New/Core/ScsiEvpd.cs
Normal file
@@ -0,0 +1,294 @@
|
||||
// /***************************************************************************
|
||||
// Aaru Data Preservation Suite
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : ScsiEvpd.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2024 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using Aaru.CommonTypes.Metadata;
|
||||
using Aaru.Decoders.SCSI;
|
||||
|
||||
namespace Aaru.Server.New.Core;
|
||||
|
||||
public static class ScsiEvpd
|
||||
{
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// </summary>
|
||||
/// <param name="pages">EVPD pages</param>
|
||||
/// <param name="vendor">SCSI vendor string</param>
|
||||
/// <param name="evpdPages">List to put the key=value pairs on</param>
|
||||
public static void Report(IEnumerable<ScsiPage> pages, string vendor,
|
||||
out Dictionary<string, List<string>> evpdPages)
|
||||
{
|
||||
evpdPages = new Dictionary<string, List<string>>();
|
||||
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<string> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
2238
Aaru.Server.New/Core/ScsiInquiry.cs
Normal file
2238
Aaru.Server.New/Core/ScsiInquiry.cs
Normal file
File diff suppressed because it is too large
Load Diff
450
Aaru.Server.New/Core/ScsiMmcFeatures.cs
Normal file
450
Aaru.Server.New/Core/ScsiMmcFeatures.cs
Normal file
@@ -0,0 +1,450 @@
|
||||
// /***************************************************************************
|
||||
// Aaru Data Preservation Suite
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : ScsiMmcFeatures.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2024 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using Aaru.CommonTypes.Metadata;
|
||||
using Aaru.CommonTypes.Structs.Devices.SCSI;
|
||||
|
||||
namespace Aaru.Server.New.Core;
|
||||
|
||||
public static class ScsiMmcFeatures
|
||||
{
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// </summary>
|
||||
/// <param name="ftr">FEATURES part of the report</param>
|
||||
/// <param name="mmcOneValue">List to put the values on</param>
|
||||
public static void Report(MmcFeatures ftr, out List<string> 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();
|
||||
}
|
||||
}
|
||||
214
Aaru.Server.New/Core/ScsiMmcMode.cs
Normal file
214
Aaru.Server.New/Core/ScsiMmcMode.cs
Normal file
@@ -0,0 +1,214 @@
|
||||
// /***************************************************************************
|
||||
// Aaru Data Preservation Suite
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : ScsiMmcMode.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2024 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using Aaru.CommonTypes.Structs.Devices.SCSI.Modes;
|
||||
|
||||
namespace Aaru.Server.New.Core;
|
||||
|
||||
public static class ScsiMmcMode
|
||||
{
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// </summary>
|
||||
/// <param name="mode">MODE PAGE 2Ah part of the report</param>
|
||||
/// <param name="mmcOneValue">List to put the values on</param>
|
||||
public static void Report(ModePage_2A mode, out List<string> 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();
|
||||
}
|
||||
}
|
||||
980
Aaru.Server.New/Core/ScsiModeSense.cs
Normal file
980
Aaru.Server.New/Core/ScsiModeSense.cs
Normal file
@@ -0,0 +1,980 @@
|
||||
// /***************************************************************************
|
||||
// Aaru Data Preservation Suite
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : ScsiModeSense.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// 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
|
||||
{
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// </summary>
|
||||
/// <param name="modeSense">MODE PAGEs part of a device report</param>
|
||||
/// <param name="vendor">SCSI vendor string</param>
|
||||
/// <param name="deviceType">SCSI peripheral device type</param>
|
||||
/// <param name="scsiOneValue">List to put values on</param>
|
||||
/// <param name="modePages">List to put key=value pairs on</param>
|
||||
public static void Report(ScsiMode modeSense, string vendor, PeripheralDeviceTypes deviceType,
|
||||
out List<string>? modeSenseCapabilities, out List<string>? blockDescriptors,
|
||||
out Dictionary<string, List<string>> modePages)
|
||||
{
|
||||
modeSenseCapabilities = null;
|
||||
blockDescriptors = null;
|
||||
modePages = new Dictionary<string, List<string>>();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user