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:
@@ -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)
|
||||
{
|
||||
<AccordionItem>
|
||||
<Table class="table-borderless table-dark" FullWidth>
|
||||
<TableBody>
|
||||
@foreach(KeyValuePair<string, string> kvp in ReadCapabilitiesDictionary)
|
||||
<AccordionHeader>
|
||||
<Heading Size="HeadingSize.Is5">
|
||||
<AccordionToggle>Read capabilities</AccordionToggle>
|
||||
</Heading>
|
||||
</AccordionHeader>
|
||||
<AccordionBody>
|
||||
<Table class="table-borderless table-dark" FullWidth>
|
||||
<TableBody>
|
||||
@foreach(KeyValuePair<string, string> kvp in ReadCapabilitiesDictionary)
|
||||
{
|
||||
<TableRow>
|
||||
<TableRowHeader>@kvp.Key</TableRowHeader>
|
||||
<TableRowCell>@kvp.Value</TableRowCell>
|
||||
</TableRow>
|
||||
}
|
||||
</TableBody>
|
||||
</Table>
|
||||
<ListGroup>
|
||||
@foreach(string cap in ReadCapabilitiesList)
|
||||
{
|
||||
<TableRow>
|
||||
<TableRowHeader>@kvp.Key</TableRowHeader>
|
||||
<TableRowCell>@kvp.Value</TableRowCell>
|
||||
</TableRow>
|
||||
<ListGroupItem>@cap</ListGroupItem>
|
||||
}
|
||||
</TableBody>
|
||||
</Table>
|
||||
<ListGroup>
|
||||
@foreach(string cap in ReadCapabilitiesList)
|
||||
</ListGroup>
|
||||
</AccordionBody>
|
||||
</AccordionItem>
|
||||
}
|
||||
@if(DeviceInquiry is not null)
|
||||
{
|
||||
<AccordionItem>
|
||||
<AccordionHeader>
|
||||
<Heading Size="HeadingSize.Is5">
|
||||
<AccordionToggle>Device inquiry</AccordionToggle>
|
||||
</Heading>
|
||||
</AccordionHeader>
|
||||
<AccordionBody>
|
||||
<Table class="table-borderless table-dark" FullWidth>
|
||||
<TableBody>
|
||||
@foreach(KeyValuePair<string, string> kvp in DeviceInquiry)
|
||||
{
|
||||
<TableRow>
|
||||
<TableRowHeader>@kvp.Key</TableRowHeader>
|
||||
<TableRowCell>@kvp.Value</TableRowCell>
|
||||
</TableRow>
|
||||
}
|
||||
</TableBody>
|
||||
</Table>
|
||||
@if(InquiryCapabilities is not null)
|
||||
{
|
||||
<ListGroupItem>@cap</ListGroupItem>
|
||||
<ListGroup>
|
||||
@foreach(string cap in InquiryCapabilities)
|
||||
{
|
||||
<ListGroupItem>@cap</ListGroupItem>
|
||||
}
|
||||
</ListGroup>
|
||||
}
|
||||
</ListGroup>
|
||||
</AccordionBody>
|
||||
</AccordionItem>
|
||||
}
|
||||
@if(ModeSenseCapabilities is not null || ModeSensePages is not null)
|
||||
{
|
||||
<AccordionItem>
|
||||
<AccordionHeader>
|
||||
<Heading Size="HeadingSize.Is5">
|
||||
<AccordionToggle>MODE SENSE pages</AccordionToggle>
|
||||
</Heading>
|
||||
</AccordionHeader>
|
||||
<AccordionBody>
|
||||
@if(ModeSenseCapabilities is not null)
|
||||
{
|
||||
<ListGroup>
|
||||
@foreach(string cap in ModeSenseCapabilities)
|
||||
{
|
||||
<ListGroupItem>@cap</ListGroupItem>
|
||||
}
|
||||
</ListGroup>
|
||||
}
|
||||
@if(BlockDescriptors is not null)
|
||||
{
|
||||
<Accordion>
|
||||
<AccordionItem>
|
||||
|
||||
<AccordionHeader>
|
||||
<Heading Size="HeadingSize.Is6">
|
||||
<AccordionToggle>Block descriptors</AccordionToggle>
|
||||
</Heading>
|
||||
</AccordionHeader>
|
||||
<AccordionBody>
|
||||
<ListGroup>
|
||||
@foreach(string descriptor in BlockDescriptors)
|
||||
{
|
||||
<ListGroupItem>@descriptor</ListGroupItem>
|
||||
}
|
||||
</ListGroup>
|
||||
</AccordionBody>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
}
|
||||
@if(ModeSensePages is not null)
|
||||
{
|
||||
foreach(KeyValuePair<string, List<string>> kvp in ModeSensePages)
|
||||
{
|
||||
<Accordion>
|
||||
<AccordionItem>
|
||||
<AccordionHeader>
|
||||
<Heading Size="HeadingSize.Is6">
|
||||
<AccordionToggle>@kvp.Key</AccordionToggle>
|
||||
</Heading>
|
||||
</AccordionHeader>
|
||||
@if(kvp.Value.Count > 0)
|
||||
{
|
||||
<AccordionBody>
|
||||
<ListGroup>
|
||||
@foreach(string cap in kvp.Value)
|
||||
{
|
||||
<ListGroupItem>@cap</ListGroupItem>
|
||||
}
|
||||
</ListGroup>
|
||||
</AccordionBody>
|
||||
}
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
}
|
||||
}
|
||||
</AccordionBody>
|
||||
</AccordionItem>
|
||||
}
|
||||
@if(EvpdPages?.Count > 0)
|
||||
{
|
||||
<AccordionItem>
|
||||
<AccordionHeader>
|
||||
<Heading Size="HeadingSize.Is5">
|
||||
<AccordionToggle>Extended Vital Product Data pages</AccordionToggle>
|
||||
</Heading>
|
||||
</AccordionHeader>
|
||||
<AccordionBody>
|
||||
@foreach(KeyValuePair<string, List<string>> kvp in EvpdPages)
|
||||
{
|
||||
<Accordion>
|
||||
<AccordionItem>
|
||||
<AccordionHeader>
|
||||
<Heading Size="HeadingSize.Is6">
|
||||
<AccordionToggle>@kvp.Key</AccordionToggle>
|
||||
</Heading>
|
||||
</AccordionHeader>
|
||||
@if(kvp.Value.Count > 0)
|
||||
{
|
||||
<AccordionBody>
|
||||
<ListGroup>
|
||||
@foreach(string cap in kvp.Value)
|
||||
{
|
||||
<ListGroupItem>@cap</ListGroupItem>
|
||||
}
|
||||
</ListGroup>
|
||||
</AccordionBody>
|
||||
}
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
}
|
||||
</AccordionBody>
|
||||
</AccordionItem>
|
||||
}
|
||||
@if(MmcModeList?.Count > 0)
|
||||
{
|
||||
<AccordionItem>
|
||||
<AccordionHeader>
|
||||
<Heading Size="HeadingSize.Is5">
|
||||
<AccordionToggle>CD-ROM capabilities</AccordionToggle>
|
||||
</Heading>
|
||||
</AccordionHeader>
|
||||
<AccordionBody>
|
||||
<ListGroup>
|
||||
@foreach(string cap in MmcModeList)
|
||||
{
|
||||
<ListGroupItem>@cap</ListGroupItem>
|
||||
}
|
||||
</ListGroup>
|
||||
</AccordionBody>
|
||||
</AccordionItem>
|
||||
}
|
||||
@if(MmcFeaturesList?.Count > 0)
|
||||
{
|
||||
<AccordionItem>
|
||||
<AccordionHeader>
|
||||
<Heading Size="HeadingSize.Is5">
|
||||
<AccordionToggle>MMC features</AccordionToggle>
|
||||
</Heading>
|
||||
</AccordionHeader>
|
||||
<AccordionBody>
|
||||
<ListGroup>
|
||||
@foreach(string feature in MmcFeaturesList)
|
||||
{
|
||||
<ListGroupItem>@feature</ListGroupItem>
|
||||
}
|
||||
</ListGroup>
|
||||
</AccordionBody>
|
||||
</AccordionItem>
|
||||
}
|
||||
@if(ScsiSscVisible)
|
||||
{
|
||||
<AccordionItem>
|
||||
<AccordionHeader>
|
||||
<Heading Size="HeadingSize.Is5">
|
||||
<AccordionToggle>SCSI Streaming device capabilities:</AccordionToggle>
|
||||
</Heading>
|
||||
</AccordionHeader>
|
||||
<AccordionBody>
|
||||
<Table class="table-borderless table-dark" FullWidth>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableRowHeader>Block size granularity</TableRowHeader>
|
||||
<TableRowCell>@ScsiSscGranularity</TableRowCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableRowHeader>Maximum block length</TableRowHeader>
|
||||
<TableRowCell>@ScsiSscMaxBlock bytes</TableRowCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableRowHeader>Minimum block length</TableRowHeader>
|
||||
<TableRowCell>@ScsiSscMinBlock bytes</TableRowCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
@if(ScsiSscDensities?.Count > 0)
|
||||
{
|
||||
foreach(SupportedDensity density in ScsiSscDensities)
|
||||
{
|
||||
<Accordion>
|
||||
<AccordionItem>
|
||||
<AccordionHeader>
|
||||
<Heading Size="HeadingSize.Is6">
|
||||
<AccordionToggle>Information for supported density with primary code @($"{density.PrimaryCode:X2}h") and secondary code @($"{density.SecondaryCode:X2}h")</AccordionToggle>
|
||||
</Heading>
|
||||
</AccordionHeader>
|
||||
<AccordionBody>
|
||||
<Table class="table-borderless table-dark" FullWidth>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableRowHeader>Drive can write this density</TableRowHeader>
|
||||
<TableRowCell>@density.Writable</TableRowCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableRowHeader>Duplicate density</TableRowHeader>
|
||||
<TableRowCell>@density.Duplicate</TableRowCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableRowHeader>Default density</TableRowHeader>
|
||||
<TableRowCell>@density.DefaultDensity</TableRowCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableRowHeader>Name</TableRowHeader>
|
||||
<TableRowCell>@density.Name</TableRowCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableRowHeader>Organization</TableRowHeader>
|
||||
<TableRowCell>@density.Organization</TableRowCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableRowHeader>Description</TableRowHeader>
|
||||
<TableRowCell>@density.Description</TableRowCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableRowHeader>Maximum capacity</TableRowHeader>
|
||||
<TableRowCell>@density.Capacity megabytes</TableRowCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableRowCell ColumnSpan="2">Density has @density.BitsPerMm bits per mm, with @density.Tracks tracks in a @density.Width mm width tape</TableRowCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
</AccordionBody>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
}
|
||||
}
|
||||
@if(ScsiSscMedias?.Count > 0)
|
||||
{
|
||||
foreach(SscSupportedMedia media in ScsiSscMedias)
|
||||
{
|
||||
<Accordion>
|
||||
<AccordionItem>
|
||||
<AccordionHeader>
|
||||
<Heading Size="HeadingSize.Is6">
|
||||
<AccordionToggle>Information for supported media with type code @($"{media.MediumType:X2}h")</AccordionToggle>
|
||||
</Heading>
|
||||
</AccordionHeader>
|
||||
<AccordionBody>
|
||||
<Table class="table-borderless table-dark" FullWidth>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableRowCell ColumnSpan="2">Media is @media.Length m long in a @media.Width mm width tape</TableRowCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableRowHeader>Name</TableRowHeader>
|
||||
<TableRowCell>@media.Name</TableRowCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableRowHeader>Organization</TableRowHeader>
|
||||
<TableRowCell>@media.Organization</TableRowCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableRowHeader>Description</TableRowHeader>
|
||||
<TableRowCell>@media.Description</TableRowCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
</AccordionBody>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
}
|
||||
}
|
||||
</AccordionBody>
|
||||
</AccordionItem>
|
||||
}
|
||||
</Accordion>
|
||||
|
||||
@@ -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<string, string>? 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<string>? SupportedAtaVersions { get; set; }
|
||||
public Dictionary<string, string>? DeviceIdentification { get; set; }
|
||||
public string? AtaTransport { get; set; }
|
||||
public List<string>? AtaTransportVersions { get; set; }
|
||||
public List<string>? GeneralConfiguration { get; set; }
|
||||
public List<string>? SpecificConfiguration { get; set; }
|
||||
public List<string>? DeviceCapabilities { get; set; }
|
||||
public List<string>? CommandSetAndFeatures { get; set; }
|
||||
public List<string>? PioTransferModes { get; set; }
|
||||
public List<string>? DmaTransferModes { get; set; }
|
||||
public List<string>? MDmaTransferModes { get; set; }
|
||||
public List<string>? UltraDmaTransferModes { get; set; }
|
||||
public List<string>? NvCache { get; set; }
|
||||
public List<string>? SmartCommandTransport { get; set; }
|
||||
public List<string>? Streaming { get; set; }
|
||||
public List<string>? Security { get; set; }
|
||||
public Dictionary<string, string>? ReadCapabilitiesDictionary { get; set; }
|
||||
public List<string>? 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<string, string>? 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<string>? SupportedAtaVersions { get; set; }
|
||||
public Dictionary<string, string>? DeviceIdentification { get; set; }
|
||||
public Dictionary<string, string>? DeviceInquiry { get; set; }
|
||||
public string? AtaTransport { get; set; }
|
||||
public List<string>? AtaTransportVersions { get; set; }
|
||||
public List<string>? GeneralConfiguration { get; set; }
|
||||
public List<string>? SpecificConfiguration { get; set; }
|
||||
public List<string>? DeviceCapabilities { get; set; }
|
||||
public List<string>? CommandSetAndFeatures { get; set; }
|
||||
public List<string>? PioTransferModes { get; set; }
|
||||
public List<string>? DmaTransferModes { get; set; }
|
||||
public List<string>? MDmaTransferModes { get; set; }
|
||||
public List<string>? UltraDmaTransferModes { get; set; }
|
||||
public List<string>? NvCache { get; set; }
|
||||
public List<string>? SmartCommandTransport { get; set; }
|
||||
public List<string>? Streaming { get; set; }
|
||||
public List<string>? Security { get; set; }
|
||||
public Dictionary<string, string>? ReadCapabilitiesDictionary { get; set; }
|
||||
public List<string>? 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<string>? InquiryCapabilities { get; set; }
|
||||
public List<string>? ModeSenseCapabilities { get; set; }
|
||||
public Dictionary<string, List<string>>? ModeSensePages { get; set; }
|
||||
public List<string>? BlockDescriptors { get; set; }
|
||||
public List<SscSupportedMedia>? ScsiSscMedias { get; set; }
|
||||
public List<SupportedDensity>? 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<string>? MmcFeaturesList { get; set; }
|
||||
public List<string>? MmcModeList { get; set; }
|
||||
public Dictionary<string, List<string>>? EvpdPages { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
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", "<br/>");
|
||||
}
|
||||
|
||||
if(report.SecureDigital.CSD != null)
|
||||
{
|
||||
Csd = Decoders.SecureDigital.Decoders.PrettifyCSD(report.SecureDigital.CSD).Replace("\n", "<br/>");
|
||||
}
|
||||
|
||||
if(report.SecureDigital.SCR != null)
|
||||
{
|
||||
Scr = Decoders.SecureDigital.Decoders.PrettifySCR(report.SecureDigital.SCR).Replace("\n", "<br/>");
|
||||
}
|
||||
|
||||
if(report.SecureDigital.OCR != null)
|
||||
{
|
||||
Ocr = Decoders.SecureDigital.Decoders.PrettifyCSD(report.SecureDigital.OCR).Replace("\n", "<br/>");
|
||||
}
|
||||
}
|
||||
|
||||
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<string, string>();
|
||||
|
||||
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<string> 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<string>? modeSenseCapabilities,
|
||||
out List<string>? blockDescriptors,
|
||||
out Dictionary<string, List<string>> modePages);
|
||||
|
||||
if(modePages.Count > 0) ModeSensePages = modePages;
|
||||
|
||||
if(modeSenseCapabilities is not null)
|
||||
{
|
||||
ModeSenseCapabilities ??= new List<string>();
|
||||
ModeSenseCapabilities.AddRange(modeSenseCapabilities);
|
||||
}
|
||||
|
||||
if(blockDescriptors is not null) BlockDescriptors = blockDescriptors;
|
||||
}
|
||||
|
||||
if(report.SCSI.EVPDPages != null)
|
||||
{
|
||||
ScsiEvpd.Report(report.SCSI.EVPDPages, vendorId, out Dictionary<string, List<string>> 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<string> mmcModeList);
|
||||
|
||||
if(mmcModeList.Count > 0) MmcModeList = mmcModeList;
|
||||
}
|
||||
|
||||
if(report.SCSI.MultiMediaDevice.Features != null)
|
||||
{
|
||||
ScsiMmcFeatures.Report(report.SCSI.MultiMediaDevice.Features, out List<string> 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<string> 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<string> readCapabilitiesList = [];
|
||||
var readCapabilitiesDictionary = new Dictionary<string, string>();
|
||||
|
||||
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;
|
||||
|
||||
|
||||
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