Files
Aaru.Server/DiscImageChef.Decoders/SCSI/Modes.cs

6781 lines
297 KiB
C#
Raw Normal View History

2015-10-24 06:58:49 +01:00
// /***************************************************************************
// The Disc Image Chef
// ----------------------------------------------------------------------------
//
// Filename : Modes.cs
// Version : 1.0
// Author(s) : Natalia Portillo
//
// Component : Component
//
// Revision : $Revision$
// Last change by : $Author$
// Date : $Date$
//
// --[ Description ] ----------------------------------------------------------
//
// Description
//
// --[ License ] --------------------------------------------------------------
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// Copyright (C) 2011-2015 Claunia.com
// ****************************************************************************/
// //$Id$
using System;
using System.Text;
2015-10-31 19:41:58 +00:00
using System.Collections.Generic;
2015-10-24 06:58:49 +01:00
namespace DiscImageChef.Decoders.SCSI
{
public static partial class Modes
2015-10-24 06:58:49 +01:00
{
public struct BlockDescriptor
{
public DensityType Density;
public ulong Blocks;
2015-10-31 18:50:15 +00:00
public uint BlockLength;
2015-10-24 06:58:49 +01:00
}
public struct ModeHeader
{
public MediumTypes MediumType;
public bool WriteProtected;
public BlockDescriptor[] BlockDescriptors;
public byte Speed;
public byte BufferedMode;
public bool EBC;
2015-10-24 19:53:59 +01:00
public bool DPOFUA;
2015-10-24 06:58:49 +01:00
}
public static ModeHeader? DecodeModeHeader6(byte[] modeResponse, PeripheralDeviceTypes deviceType)
{
2016-04-19 02:11:47 +01:00
if(modeResponse == null || modeResponse.Length < 4 || modeResponse.Length < modeResponse[0] + 1)
2015-10-24 06:58:49 +01:00
return null;
ModeHeader header = new ModeHeader();
header.MediumType = (MediumTypes)modeResponse[1];
2016-04-19 02:11:47 +01:00
if(modeResponse[3] > 0)
2015-10-24 06:58:49 +01:00
{
2015-10-25 05:39:25 +00:00
header.BlockDescriptors = new BlockDescriptor[modeResponse[3] / 8];
2016-04-19 02:11:47 +01:00
for(int i = 0; i < header.BlockDescriptors.Length; i++)
2015-10-24 06:58:49 +01:00
{
header.BlockDescriptors[i].Density = (DensityType)modeResponse[0 + i * 8 + 4];
header.BlockDescriptors[i].Blocks += (ulong)(modeResponse[1 + i * 8 + 4] << 16);
header.BlockDescriptors[i].Blocks += (ulong)(modeResponse[2 + i * 8 + 4] << 8);
header.BlockDescriptors[i].Blocks += modeResponse[3 + i * 8 + 4];
2015-10-31 18:50:15 +00:00
header.BlockDescriptors[i].BlockLength += (uint)(modeResponse[5 + i * 8 + 4] << 16);
header.BlockDescriptors[i].BlockLength += (uint)(modeResponse[6 + i * 8 + 4] << 8);
2015-10-24 06:58:49 +01:00
header.BlockDescriptors[i].BlockLength += modeResponse[7 + i * 8 + 4];
}
}
2016-04-19 02:11:47 +01:00
if(deviceType == PeripheralDeviceTypes.DirectAccess || deviceType == PeripheralDeviceTypes.MultiMediaDevice)
2015-10-24 19:53:59 +01:00
{
2015-10-24 06:58:49 +01:00
header.WriteProtected = ((modeResponse[2] & 0x80) == 0x80);
2015-10-24 19:53:59 +01:00
header.DPOFUA = ((modeResponse[2] & 0x10) == 0x10);
}
2015-10-24 06:58:49 +01:00
2016-04-19 02:11:47 +01:00
if(deviceType == PeripheralDeviceTypes.SequentialAccess)
2015-10-24 06:58:49 +01:00
{
header.WriteProtected = ((modeResponse[2] & 0x80) == 0x80);
header.Speed = (byte)(modeResponse[2] & 0x0F);
header.BufferedMode = (byte)((modeResponse[2] & 0x70) >> 4);
}
2016-04-19 02:11:47 +01:00
if(deviceType == PeripheralDeviceTypes.PrinterDevice)
2015-10-24 06:58:49 +01:00
header.BufferedMode = (byte)((modeResponse[2] & 0x70) >> 4);
2016-04-19 02:11:47 +01:00
if(deviceType == PeripheralDeviceTypes.OpticalDevice)
2015-10-24 06:58:49 +01:00
{
header.WriteProtected = ((modeResponse[2] & 0x80) == 0x80);
header.EBC = ((modeResponse[2] & 0x01) == 0x01);
2015-10-24 19:53:59 +01:00
header.DPOFUA = ((modeResponse[2] & 0x10) == 0x10);
2015-10-24 06:58:49 +01:00
}
return header;
}
public static string PrettifyModeHeader6(byte[] modeResponse, PeripheralDeviceTypes deviceType)
{
return PrettifyModeHeader(DecodeModeHeader6(modeResponse, deviceType), deviceType);
}
public static string PrettifyModeHeader(ModeHeader? header, PeripheralDeviceTypes deviceType)
{
2016-04-19 02:11:47 +01:00
if(!header.HasValue)
2015-10-24 06:58:49 +01:00
return null;
StringBuilder sb = new StringBuilder();
sb.AppendLine("SCSI Mode Sense Header:");
2015-10-24 06:58:49 +01:00
2016-04-19 02:11:47 +01:00
switch(deviceType)
2015-10-24 06:58:49 +01:00
{
#region Direct access device mode header
2015-10-24 06:58:49 +01:00
case PeripheralDeviceTypes.DirectAccess:
{
2016-04-19 02:11:47 +01:00
if(header.Value.MediumType != MediumTypes.Default)
2015-10-24 06:58:49 +01:00
{
sb.Append("\tMedium is ");
2015-10-25 02:07:39 +00:00
2016-04-19 02:11:47 +01:00
switch(header.Value.MediumType)
2015-10-25 02:07:39 +00:00
{
case MediumTypes.ECMA54:
sb.AppendLine("ECMA-54: 200 mm Flexible Disk Cartridge using Two-Frequency Recording at 13262 ftprad on One Side");
break;
case MediumTypes.ECMA59:
sb.AppendLine("ECMA-59 & ANSI X3.121-1984: 200 mm Flexible Disk Cartridge using Two-Frequency Recording at 13262 ftprad on Both Sides");
break;
case MediumTypes.ECMA69:
sb.AppendLine("ECMA-69: 200 mm Flexible Disk Cartridge using MFM Recording at 13262 ftprad on Both Sides");
break;
case MediumTypes.ECMA66:
sb.AppendLine("ECMA-66: 130 mm Flexible Disk Cartridge using Two-Frequency Recording at 7958 ftprad on One Side");
break;
case MediumTypes.ECMA70:
sb.AppendLine("ECMA-70 & ANSI X3.125-1985: 130 mm Flexible Disk Cartridge using MFM Recording at 7958 ftprad on Both Sides; 1,9 Tracks per mm");
break;
case MediumTypes.ECMA78:
sb.AppendLine("ECMA-78 & ANSI X3.126-1986: 130 mm Flexible Disk Cartridge using MFM Recording at 7958 ftprad on Both Sides; 3,8 Tracks per mm");
break;
case MediumTypes.ECMA99:
sb.AppendLine("ECMA-99 & ISO 8630-1985: 130 mm Flexible Disk Cartridge using MFM Recording at 13262 ftprad on Both Sides; 3,8 Tracks per mm");
break;
case MediumTypes.ECMA100:
sb.AppendLine("ECMA-100 & ANSI X3.137: 90 mm Flexible Disk Cartridge using MFM Recording at 7859 ftprad on Both Sides; 5,3 Tracks per mm");
break;
// Most probably they will never appear, but magneto-opticals use these codes
/*
2015-10-25 02:07:39 +00:00
case MediumTypes.Unspecified_SS:
sb.AppendLine("Unspecified single sided flexible disk");
break;
case MediumTypes.Unspecified_DS:
sb.AppendLine("Unspecified double sided flexible disk");
break;
*/
2015-10-25 02:07:39 +00:00
case MediumTypes.X3_73:
sb.AppendLine("ANSI X3.73-1980: 200 mm, 6631 ftprad, 1,9 Tracks per mm, 1 side");
break;
case MediumTypes.X3_73_DS:
sb.AppendLine("ANSI X3.73-1980: 200 mm, 6631 ftprad, 1,9 Tracks per mm, 2 sides");
break;
case MediumTypes.X3_82:
sb.AppendLine("ANSI X3.80-1980: 130 mm, 3979 ftprad, 1,9 Tracks per mm, 1 side");
break;
case MediumTypes.Type3Floppy:
sb.AppendLine("3.5-inch, 135 tpi, 12362 bits/radian, double-sided MFM (aka 1.25Mb)");
break;
case MediumTypes.HDFloppy:
sb.AppendLine("3.5-inch, 135 tpi, 15916 bits/radian, double-sided MFM (aka 1.44Mb)");
break;
case MediumTypes.ReadOnly:
sb.AppendLine("a Read-only optical");
break;
case MediumTypes.WORM:
sb.AppendLine("a Write-once Read-many optical");
break;
case MediumTypes.Erasable:
sb.AppendLine("a Erasable optical");
break;
case MediumTypes.RO_WORM:
sb.AppendLine("a combination of read-only and write-once optical");
break;
// These magneto-opticals were never manufactured
/*
case MediumTypes.RO_RW:
sb.AppendLine("a combination of read-only and erasable optical");
break;
case MediumTypes.WORM_RW:
sb.AppendLine("a combination of write-once and erasable optical");
break;
*/
case MediumTypes.DOW:
sb.AppendLine("a direct-overwrite optical");
break;
2015-10-25 02:07:39 +00:00
default:
sb.AppendFormat("Unknown medium type 0x{0:X2}", (byte)header.Value.MediumType).AppendLine();
2015-10-25 02:07:39 +00:00
break;
}
2015-10-24 06:58:49 +01:00
}
2016-04-19 02:11:47 +01:00
if(header.Value.WriteProtected)
sb.AppendLine("\tMedium is write protected");
2015-10-24 19:53:59 +01:00
2016-04-19 02:11:47 +01:00
if(header.Value.DPOFUA)
sb.AppendLine("\tDrive supports DPO and FUA bits");
2015-10-24 19:53:59 +01:00
2016-04-19 02:11:47 +01:00
if(header.Value.BlockDescriptors != null)
2015-10-24 06:58:49 +01:00
{
2016-04-19 02:11:47 +01:00
foreach(BlockDescriptor descriptor in header.Value.BlockDescriptors)
2015-10-24 06:58:49 +01:00
{
string density = "";
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.Default:
break;
case DensityType.Flux7958:
density = "7958 flux transitions per radian";
break;
case DensityType.Flux13262:
density = "13262 flux transitions per radian";
break;
case DensityType.Flux15916:
density = "15916 flux transitions per radian";
break;
default:
density = String.Format("with unknown density code 0x{0:X2}", (byte)descriptor.Density);
break;
}
2015-10-24 06:58:49 +01:00
2016-04-19 02:11:47 +01:00
if(density != "")
{
2016-04-19 02:11:47 +01:00
if(descriptor.Blocks == 0)
sb.AppendFormat("\tAll remaining blocks have {0} and are {1} bytes each", density, descriptor.BlockLength).AppendLine();
else
sb.AppendFormat("\t{0} blocks have {1} and are {2} bytes each", descriptor.Blocks, density, descriptor.BlockLength).AppendLine();
}
2015-10-24 19:53:59 +01:00
else
{
2016-04-19 02:11:47 +01:00
if(descriptor.Blocks == 0)
sb.AppendFormat("\tAll remaining blocks are {0} bytes each", descriptor.BlockLength).AppendLine();
else
sb.AppendFormat("\t{0} blocks are {1} bytes each", descriptor.Blocks, descriptor.BlockLength).AppendLine();
}
2015-10-24 19:53:59 +01:00
}
2015-10-24 06:58:49 +01:00
}
break;
}
2016-04-19 02:11:47 +01:00
#endregion Direct access device mode header
#region Sequential access device mode header
2015-10-24 06:58:49 +01:00
case PeripheralDeviceTypes.SequentialAccess:
{
2016-04-19 02:11:47 +01:00
switch(header.Value.BufferedMode)
2015-10-24 06:58:49 +01:00
{
case 0:
sb.AppendLine("\tDevice writes directly to media");
2015-10-24 06:58:49 +01:00
break;
case 1:
sb.AppendLine("\tDevice uses a write cache");
2015-10-24 06:58:49 +01:00
break;
2015-10-24 19:53:59 +01:00
case 2:
sb.AppendLine("\tDevice uses a write cache but doesn't return until cache is flushed");
2015-10-24 19:53:59 +01:00
break;
2015-10-24 06:58:49 +01:00
default:
sb.AppendFormat("\tUnknown buffered mode code 0x{0:X2}", (byte)header.Value.BufferedMode).AppendLine();
2015-10-24 06:58:49 +01:00
break;
}
2016-04-19 02:11:47 +01:00
if(header.Value.Speed == 0)
sb.AppendLine("\tDevice uses default speed");
2015-10-24 06:58:49 +01:00
else
sb.AppendFormat("\tDevice uses speed {0}", header.Value.Speed).AppendLine();
2015-10-24 06:58:49 +01:00
2016-04-19 02:11:47 +01:00
if(header.Value.WriteProtected)
sb.AppendLine("\tMedium is write protected");
2015-10-24 06:58:49 +01:00
string medium = "";
2016-04-19 02:11:47 +01:00
switch(header.Value.MediumType)
{
case MediumTypes.Default:
medium = "undefined";
break;
case MediumTypes.Tape12:
medium = "6,3 mm tape with 12 tracks at 394 ftpmm or DC-9250";
break;
case MediumTypes.Tape24:
medium = "6,3 mm tape with 24 tracks at 394 ftpmm or MLR1-26GBSL";
break;
case MediumTypes.LTOWORM:
medium = "LTO Ultrium WORM or cleaning cartridge";
break;
case MediumTypes.LTO:
medium = "LTO Ultrium";
break;
case MediumTypes.LTO2:
medium = "LTO Ultrium-2";
break;
case MediumTypes.DC2900SL:
medium = "DC-2900SL";
break;
case MediumTypes.MLR1:
medium = "MLR1-26GB or DDS-3";
break;
case MediumTypes.DC9200:
medium = "DC-9200 or DDS-4";
break;
case MediumTypes.DAT72:
medium = "DAT-72";
break;
case MediumTypes.LTO3:
medium = "LTO Ultrium-3";
break;
case MediumTypes.LTO3WORM:
medium = "LTO Ultrium-3 WORM";
break;
case MediumTypes.DDSCleaning:
medium = "DDS cleaning cartridge";
break;
case MediumTypes.SLR32:
medium = "SLR-32";
break;
case MediumTypes.SLRtape50:
medium = "SLRtape-50";
break;
case MediumTypes.LTO4:
medium = "LTO Ultrium-4";
break;
case MediumTypes.LTO4WORM:
medium = "LTO Ultrium-4 WORM";
break;
case MediumTypes.SLRtape50SL:
medium = "SLRtape-50 SL";
break;
case MediumTypes.SLR32SL:
medium = "SLR-32SL";
break;
case MediumTypes.SLR5:
medium = "SLR-5";
break;
case MediumTypes.SLR5SL:
medium = "SLR-5SL";
break;
case MediumTypes.LTO5:
medium = "LTO Ultrium-5";
break;
case MediumTypes.LTO5WORM:
medium = "LTO Ultrium-5 WORM";
break;
case MediumTypes.SLRtape7:
medium = "SLRtape-7";
break;
case MediumTypes.SLRtape7SL:
medium = "SLRtape-7 SL";
break;
case MediumTypes.SLRtape24:
medium = "SLRtape-24";
break;
case MediumTypes.SLRtape24SL:
medium = "SLRtape-24 SL";
break;
case MediumTypes.LTO6:
medium = "LTO Ultrium-6";
break;
case MediumTypes.LTO6WORM:
medium = "LTO Ultrium-6 WORM";
break;
case MediumTypes.SLRtape140:
medium = "SLRtape-140";
break;
case MediumTypes.SLRtape40:
medium = "SLRtape-40";
break;
case MediumTypes.SLRtape60:
medium = "SLRtape-60 or SLRtape-75";
break;
case MediumTypes.SLRtape100:
medium = "SLRtape-100";
break;
case MediumTypes.SLR40_60_100:
medium = "SLR-40, SLR-60 or SLR-100";
break;
case MediumTypes.LTO7:
medium = "LTO Ultrium-7";
break;
case MediumTypes.LTO7WORM:
medium = "LTO Ultrium-7 WORM";
break;
case MediumTypes.LTOCD:
medium = "LTO Ultrium";
break;
case MediumTypes.Exatape15m:
medium = "Exatape 15m, IBM MagStar or VXA";
break;
case MediumTypes.CT1:
medium = "CompactTape I, Exatape 28m, CompactTape II, VXA-2 or VXA-3";
break;
case MediumTypes.Exatape54m:
medium = "Exatape 54m or DLTtape III";
break;
case MediumTypes.Exatape80m:
medium = "Exatape 80m or DLTtape IIIxt";
break;
case MediumTypes.Exatape106m:
medium = "Exatape 106m, DLTtape IV or Travan 5";
break;
case MediumTypes.Exatape106mXL:
medium = "Exatape 160m XL or Super DLTtape I";
break;
case MediumTypes.SDLT2:
medium = "Super DLTtape II";
break;
case MediumTypes.VStapeI:
medium = "VStape I";
break;
case MediumTypes.DLTtapeS4:
medium = "DLTtape S4";
break;
case MediumTypes.Travan7:
medium = "Travan 7";
break;
case MediumTypes.Exatape22m:
medium = "Exatape 22m";
break;
case MediumTypes.Exatape40m:
medium = "Exatape 40m";
break;
case MediumTypes.Exatape76m:
medium = "Exatape 76m";
break;
case MediumTypes.Exatape112m:
medium = "Exatape 112m";
break;
case MediumTypes.Exatape22mAME:
medium = "Exatape 22m AME";
break;
case MediumTypes.Exatape170m:
medium = "Exatape 170m";
break;
case MediumTypes.Exatape125m:
medium = "Exatape 125m";
break;
case MediumTypes.Exatape45m:
medium = "Exatape 45m";
break;
case MediumTypes.Exatape225m:
medium = "Exatape 225m";
break;
case MediumTypes.Exatape150m:
medium = "Exatape 150m";
break;
case MediumTypes.Exatape75m:
medium = "Exatape 75m";
break;
default:
medium = String.Format("unknown medium type 0x{0:X2}", (byte)header.Value.MediumType);
break;
}
sb.AppendFormat("\tMedium is {0}", medium).AppendLine();
2016-04-19 02:11:47 +01:00
if(header.Value.BlockDescriptors != null)
2015-10-24 06:58:49 +01:00
{
2016-04-19 02:11:47 +01:00
foreach(BlockDescriptor descriptor in header.Value.BlockDescriptors)
2015-10-24 06:58:49 +01:00
{
string density = "";
2016-04-19 02:11:47 +01:00
switch(header.Value.MediumType)
2015-10-24 19:53:59 +01:00
{
case MediumTypes.Default:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.Default:
break;
case DensityType.ECMA62:
density = "ECMA-62 & ANSI X3.22-1983: 12,7 mm 9-Track Magnetic Tape, 32 ftpmm, NRZI, 32 cpmm";
break;
case DensityType.ECMA62_Phase:
density = "ECMA-62 & ANSI X3.39-1986: 12,7 mm 9-Track Magnetic Tape, 126 ftpmm, Phase Encoding, 63 cpmm";
break;
case DensityType.ECMA62_GCR:
density = "ECMA-62 & ANSI X3.54-1986: 12,7 mm 9-Track Magnetic Tape, 356 ftpmm, NRZI, 245 cpmm GCR";
break;
case DensityType.ECMA79:
density = "ECMA-79 & ANSI X3.116-1986: 6,30 mm Magnetic Tape Cartridge, 252 ftpmm, MFM";
break;
case DensityType.IBM3480:
density = "Draft ECMA & ANSI X3B5/87-099: 12,7 mm 18-Track Magnetic Tape Cartridge, 1944 ftpmm, IFM, GCR (IBM 3480, 3490, 3490E)";
break;
case DensityType.ECMA46:
density = "ECMA-46 & ANSI X3.56-1986: 6,30 mm Magnetic Tape Cartridge, Phase Encoding, 63 bpmm";
break;
case DensityType.ECMA98:
density = "ECMA-98: 6,30 mm Magnetic Tape Cartridge, NRZI, 394 ftpmm";
break;
case DensityType.X3_136:
density = "ANXI X3.136-1986: 6,3 mm 4 or 9-Track Magnetic Tape Cartridge, 315 bpmm, GCR (QIC-24)";
break;
case DensityType.X3_157:
density = "ANXI X3.157-1987: 12,7 mm 9-Track Magnetic Tape, 126 bpmm, Phase Encoding";
break;
case DensityType.X3_158:
density = "ANXI X3.158-1987: 3,81 mm 4-Track Magnetic Tape Cassette, 315 bpmm, GCR";
break;
case DensityType.X3B5_86:
density = "ANXI X3B5/86-199: 12,7 mm 22-Track Magnetic Tape Cartridge, 262 bpmm, MFM";
break;
case DensityType.HiTC1:
density = "HI-TC1: 12,7 mm 24-Track Magnetic Tape Cartridge, 500 bpmm, GCR";
break;
case DensityType.HiTC2:
density = "HI-TC2: 12,7 mm 24-Track Magnetic Tape Cartridge, 999 bpmm, GCR";
break;
case DensityType.QIC120:
density = "QIC-120: 6,3 mm 15-Track Magnetic Tape Cartridge, 394 bpmm, GCR";
break;
case DensityType.QIC150:
density = "QIC-150: 6,3 mm 18-Track Magnetic Tape Cartridge, 394 bpmm, GCR";
break;
case DensityType.QIC320:
density = "QIC-320: 6,3 mm 26-Track Magnetic Tape Cartridge, 630 bpmm, GCR";
break;
case DensityType.QIC1350:
density = "QIC-1350: 6,3 mm 30-Track Magnetic Tape Cartridge, 2034 bpmm, RLL";
break;
case DensityType.X3B5_88:
density = "ANXI X3B5/88-185A: 3,81 mm Magnetic Tape Cassette, 2400 bpmm, DDS";
break;
case DensityType.X3_202:
density = "ANXI X3.202-1991: 8 mm Magnetic Tape Cassette, 1703 bpmm, RLL";
break;
case DensityType.ECMA_TC17:
density = "ECMA TC17: 8 mm Magnetic Tape Cassette, 1789 bpmm, RLL";
break;
case DensityType.X3_193:
density = "ANXI X3.193-1990: 12,7 mm 48-Track Magnetic Tape Cartridge, 394 bpmm, MFM";
break;
case DensityType.X3B5_91:
density = "ANXI X3B5/97-174: 12,7 mm 48-Track Magnetic Tape Cartridge, 1673 bpmm, MFM";
break;
case DensityType.QIC11:
density = "QIC-11";
break;
case DensityType.IBM3490E:
density = "IBM 3490E";
break;
case DensityType.LTO1:
2016-04-19 02:11:47 +01:00
//case DensityType.SAIT1:
density = "LTO Ultrium or Super AIT-1";
break;
case DensityType.LTO2Old:
density = "LTO Ultrium-2";
break;
case DensityType.LTO2:
2016-04-19 02:11:47 +01:00
//case DensityType.T9840:
density = "LTO Ultrium-2 or T9840";
break;
case DensityType.T9940:
density = "T9940";
break;
case DensityType.LTO3:
2016-04-19 02:11:47 +01:00
//case DensityType.T9940:
density = "LTO Ultrium-3 or T9940";
break;
case DensityType.T9840C:
density = "T9840C";
break;
case DensityType.LTO4:
2016-04-19 02:11:47 +01:00
//case DensityType.T9840D:
density = "LTO Ultrium-4 or T9840D";
break;
case DensityType.T10000A:
density = "T10000A";
break;
case DensityType.T10000B:
density = "T10000B";
break;
case DensityType.T10000C:
density = "T10000C";
break;
case DensityType.T10000D:
density = "T10000D";
break;
case DensityType.AIT1:
density = "AIT-1";
break;
case DensityType.AIT2:
density = "AIT-2";
break;
case DensityType.AIT3:
density = "AIT-3";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
case MediumTypes.LTOWORM:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.Default:
density = "LTO Ultrium cleaning cartridge";
break;
case DensityType.LTO3:
density = "LTO Ultrium-3 WORM";
break;
case DensityType.LTO4:
density = "LTO Ultrium-4 WORM";
break;
case DensityType.LTO5:
density = "LTO Ultrium-5 WORM";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
2016-04-19 02:11:47 +01:00
}
break;
case MediumTypes.LTO:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.LTO1:
density = "LTO Ultrium";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
case MediumTypes.LTO2:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.LTO2:
density = "LTO Ultrium-2";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
case MediumTypes.DDS3:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.Default:
density = "MLR1-26GB";
break;
case DensityType.DDS3:
density = "DDS-3";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
case MediumTypes.DDS4:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.Default:
density = "DC-9200";
break;
case DensityType.DDS4:
density = "DDS-4";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
case MediumTypes.DAT72:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.DAT72:
density = "DAT-72";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
case MediumTypes.LTO3:
case MediumTypes.LTO3WORM:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.LTO3:
density = "LTO Ultrium-3";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
case MediumTypes.DDSCleaning:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.Default:
density = "DDS cleaning cartridge";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
case MediumTypes.LTO4:
case MediumTypes.LTO4WORM:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.LTO4:
density = "LTO Ultrium-4";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
case MediumTypes.LTO5:
case MediumTypes.LTO5WORM:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.LTO5:
density = "LTO Ultrium-5";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
case MediumTypes.LTO6:
case MediumTypes.LTO6WORM:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.LTO6:
density = "LTO Ultrium-6";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
case MediumTypes.LTO7:
case MediumTypes.LTO7WORM:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.LTO7:
density = "LTO Ultrium-7";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
case MediumTypes.LTOCD:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.LTO2:
density = "LTO Ultrium-2 in CD emulation mode";
break;
case DensityType.LTO3:
density = "LTO Ultrium-3 in CD emulation mode";
break;
case DensityType.LTO4:
density = "LTO Ultrium-4 in CD emulation mode";
break;
case DensityType.LTO5:
density = "LTO Ultrium-5 in CD emulation mode";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
case MediumTypes.Exatape15m:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.Ex8200:
density = "EXB-8200";
break;
case DensityType.Ex8200c:
density = "EXB-8200 compressed";
break;
case DensityType.Ex8500:
density = "EXB-8500";
break;
case DensityType.Ex8500c:
density = "EXB-8500 compressed";
break;
case DensityType.Mammoth:
density = "Mammoth";
break;
case DensityType.IBM3590:
density = "IBM 3590";
break;
case DensityType.IBM3590E:
density = "IBM 3590E";
break;
case DensityType.VXA1:
density = "VXA-1";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
case MediumTypes.Exatape28m:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.Ex8200:
density = "EXB-8200";
break;
case DensityType.Ex8200c:
density = "EXB-8200 compressed";
break;
case DensityType.Ex8500:
density = "EXB-8500";
break;
case DensityType.Ex8500c:
density = "EXB-8500 compressed";
break;
case DensityType.Mammoth:
density = "Mammoth";
break;
case DensityType.CT1:
density = "CompactTape I";
break;
case DensityType.CT2:
density = "CompactTape II";
break;
case DensityType.IBM3590:
density = "IBM 3590 extended";
break;
case DensityType.IBM3590E:
density = "IBM 3590E extended";
break;
case DensityType.VXA2:
density = "VXA-2";
break;
case DensityType.VXA3:
density = "VXA-3";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
case MediumTypes.Exatape54m:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.Ex8200:
density = "EXB-8200";
break;
case DensityType.Ex8200c:
density = "EXB-8200 compressed";
break;
case DensityType.Ex8500:
density = "EXB-8500";
break;
case DensityType.Ex8500c:
density = "EXB-8500 compressed";
break;
case DensityType.Mammoth:
density = "Mammoth";
break;
case DensityType.DLT3_42k:
density = "DLTtape III at 42500 bpi";
break;
case DensityType.DLT3_56t:
density = "DLTtape III with 56 tracks";
break;
case DensityType.DLT3_62k:
case DensityType.DLT3_62kAlt:
density = "DLTtape III at 62500 bpi";
break;
case DensityType.DLT3c:
density = "DLTtape III compressed";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
case MediumTypes.Exatape80m:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.Ex8200:
density = "EXB-8200";
break;
case DensityType.Ex8200c:
density = "EXB-8200 compressed";
break;
case DensityType.Ex8500:
density = "EXB-8500";
break;
case DensityType.Ex8500c:
density = "EXB-8500 compressed";
break;
case DensityType.Mammoth:
density = "Mammoth";
break;
case DensityType.DLT3_62k:
case DensityType.DLT3_62kAlt:
density = "DLTtape IIIxt";
break;
case DensityType.DLT3c:
density = "DLTtape IIIxt compressed";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
case MediumTypes.Exatape106m:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.Ex8200:
density = "EXB-8200";
break;
case DensityType.Ex8200c:
density = "EXB-8200 compressed";
break;
case DensityType.Ex8500:
density = "EXB-8500";
break;
case DensityType.Ex8500c:
density = "EXB-8500 compressed";
break;
case DensityType.Mammoth:
density = "Mammoth";
break;
case DensityType.DLT4:
case DensityType.DLT4Alt:
density = "DLTtape IV";
break;
case DensityType.DLT4_123k:
case DensityType.DLT4_123kAlt:
density = "DLTtape IV at 123090 bpi";
break;
case DensityType.DLT4_98k:
density = "DLTtape IV at 98250 bpi";
break;
case DensityType.Travan5:
density = "Travan 5";
break;
case DensityType.DLT4c:
density = "DLTtape IV compressed";
break;
case DensityType.DLT4_85k:
density = "DLTtape IV at 85937 bpi";
break;
case DensityType.DLT4c_85k:
density = "DLTtape IV at 85937 bpi compressed";
break;
case DensityType.DLT4c_123k:
density = "DLTtape IV at 123090 bpi compressed";
break;
case DensityType.DLT4c_98k:
density = "DLTtape IV at 98250 bpi compressed";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
case MediumTypes.Exatape106mXL:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.Ex8200:
density = "EXB-8200";
break;
case DensityType.Ex8200c:
density = "EXB-8200 compressed";
break;
case DensityType.Ex8500:
density = "EXB-8500";
break;
case DensityType.Ex8500c:
density = "EXB-8500 compressed";
break;
case DensityType.Mammoth:
density = "Mammoth";
break;
case DensityType.SDLT1_133k:
case DensityType.SDLT1_133kAlt:
density = "Super DLTtape I at 133000 bpi";
break;
case DensityType.SDLT1:
2016-04-19 02:11:47 +01:00
//case DensityType.SDLT1Alt:
density = "Super DLTtape I";
break;
case DensityType.SDLT1c:
density = "Super DLTtape I compressed";
break;
/*case DensityType.SDLT1_133kAlt:
density = "Super DLTtape I at 133000 bpi compressed";
break;*/
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
case MediumTypes.SDLT2:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.SDLT2:
density = "Super DLTtape II";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
case MediumTypes.VStapeI:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.VStape1:
case DensityType.VStape1Alt:
density = "VStape I";
break;
case DensityType.VStape1c:
density = "VStape I compressed";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
case MediumTypes.DLTtapeS4:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.DLTS4:
density = "DLTtape S4";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
case MediumTypes.Exatape22m:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.Ex8200:
density = "EXB-8200";
break;
case DensityType.Ex8200c:
density = "EXB-8200 compressed";
break;
case DensityType.Ex8500:
density = "EXB-8500";
break;
case DensityType.Ex8500c:
density = "EXB-8500 compressed";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
case MediumTypes.Exatape40m:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.Ex8200:
density = "EXB-8200";
break;
case DensityType.Ex8200c:
density = "EXB-8200 compressed";
break;
case DensityType.Ex8500:
density = "EXB-8500";
break;
case DensityType.Ex8500c:
density = "EXB-8500 compressed";
break;
case DensityType.Mammoth:
density = "Mammoth";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
case MediumTypes.Exatape76m:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.Ex8200:
density = "EXB-8200";
break;
case DensityType.Ex8200c:
density = "EXB-8200 compressed";
break;
case DensityType.Ex8500:
density = "EXB-8500";
break;
case DensityType.Ex8500c:
density = "EXB-8500 compressed";
break;
case DensityType.Mammoth:
density = "Mammoth";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
case MediumTypes.Exatape112m:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.Ex8200:
density = "EXB-8200";
break;
case DensityType.Ex8200c:
density = "EXB-8200 compressed";
break;
case DensityType.Ex8500:
density = "EXB-8500";
break;
case DensityType.Ex8500c:
density = "EXB-8500 compressed";
break;
case DensityType.Mammoth:
density = "Mammoth";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
case MediumTypes.Exatape22mAME:
case MediumTypes.Exatape170m:
case MediumTypes.Exatape125m:
case MediumTypes.Exatape45m:
case MediumTypes.Exatape225m:
case MediumTypes.Exatape150m:
case MediumTypes.Exatape75m:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.Mammoth:
density = "Mammoth";
break;
case DensityType.Mammoth2:
density = "Mammoth-2";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
case MediumTypes.DC2900SL:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.Default:
density = "DC-2900SL";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
case MediumTypes.DC9250:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.Default:
density = "DC-9250";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
case MediumTypes.SLR32:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.Default:
density = "SLR-32";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
case MediumTypes.MLR1SL:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.Default:
density = "MRL1-26GBSL";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
case MediumTypes.SLRtape50:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.Default:
density = "SLRtape-50";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
case MediumTypes.SLRtape50SL:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.Default:
density = "SLRtape-50 SL";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
case MediumTypes.SLR32SL:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.Default:
density = "SLR-32 SL";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
case MediumTypes.SLR5:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.Default:
density = "SLR-5";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
case MediumTypes.SLR5SL:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.Default:
density = "SLR-5 SL";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
case MediumTypes.SLRtape7:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.Default:
density = "SLRtape-7";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
case MediumTypes.SLRtape7SL:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.Default:
density = "SLRtape-7 SL";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
case MediumTypes.SLRtape24:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.Default:
density = "SLRtape-24";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
case MediumTypes.SLRtape24SL:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.Default:
density = "SLRtape-24 SL";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
case MediumTypes.SLRtape140:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.Default:
density = "SLRtape-140";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
case MediumTypes.SLRtape40:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.Default:
density = "SLRtape-40";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
case MediumTypes.SLRtape60:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.Default:
density = "SLRtape-60 or SLRtape-75";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
case MediumTypes.SLRtape100:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.Default:
density = "SLRtape-100";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
case MediumTypes.SLR40_60_100:
{
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.Default:
density = "SLR40, SLR60 or SLR100";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
}
}
break;
2016-04-19 02:11:47 +01:00
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
2015-10-24 19:53:59 +01:00
}
2016-04-19 02:11:47 +01:00
if(density != "")
2015-10-24 19:53:59 +01:00
{
2016-04-19 02:11:47 +01:00
if(descriptor.Blocks == 0)
{
2016-04-19 02:11:47 +01:00
if(descriptor.BlockLength == 0)
sb.AppendFormat("\tAll remaining blocks conform to {0} and have a variable length", density).AppendLine();
else
sb.AppendFormat("\tAll remaining blocks conform to {0} and are {1} bytes each", density, descriptor.BlockLength).AppendLine();
}
2015-10-24 19:53:59 +01:00
else
{
2016-04-19 02:11:47 +01:00
if(descriptor.BlockLength == 0)
sb.AppendFormat("\t{0} blocks conform to {1} and have a variable length", descriptor.Blocks, density).AppendLine();
else
sb.AppendFormat("\t{0} blocks conform to {1} and are {2} bytes each", descriptor.Blocks, density, descriptor.BlockLength).AppendLine();
}
2015-10-24 19:53:59 +01:00
}
2015-10-24 06:58:49 +01:00
else
2015-10-24 19:53:59 +01:00
{
2016-04-19 02:11:47 +01:00
if(descriptor.Blocks == 0)
{
2016-04-19 02:11:47 +01:00
if(descriptor.BlockLength == 0)
sb.AppendFormat("\tAll remaining blocks have a variable length").AppendLine();
else
sb.AppendFormat("\tAll remaining blocks are {0} bytes each", descriptor.BlockLength).AppendLine();
}
2015-10-24 19:53:59 +01:00
else
{
2016-04-19 02:11:47 +01:00
if(descriptor.BlockLength == 0)
sb.AppendFormat("\t{0} blocks have a variable length", descriptor.Blocks).AppendLine();
else
sb.AppendFormat("\t{0} blocks are {1} bytes each", descriptor.Blocks, descriptor.BlockLength).AppendLine();
}
2015-10-24 19:53:59 +01:00
}
2015-10-24 06:58:49 +01:00
}
}
break;
}
#endregion Sequential access device mode header
#region Printer device mode header
2015-10-24 06:58:49 +01:00
case PeripheralDeviceTypes.PrinterDevice:
{
2016-04-19 02:11:47 +01:00
switch(header.Value.BufferedMode)
2015-10-24 06:58:49 +01:00
{
case 0:
sb.AppendLine("\tDevice prints directly");
2015-10-24 06:58:49 +01:00
break;
case 1:
sb.AppendLine("\tDevice uses a print cache");
2015-10-24 06:58:49 +01:00
break;
default:
sb.AppendFormat("\tUnknown buffered mode code 0x{0:X2}", header.Value.BufferedMode).AppendLine();
2015-10-24 06:58:49 +01:00
break;
}
break;
}
#endregion Printer device mode header
#region Optical device mode header
2015-10-24 06:58:49 +01:00
case PeripheralDeviceTypes.OpticalDevice:
{
2016-04-19 02:11:47 +01:00
if(header.Value.MediumType != MediumTypes.Default)
2015-10-25 02:07:39 +00:00
{
sb.Append("\tMedium is ");
2015-10-25 02:07:39 +00:00
2016-04-19 02:11:47 +01:00
switch(header.Value.MediumType)
2015-10-25 02:07:39 +00:00
{
case MediumTypes.ReadOnly:
sb.AppendLine("a Read-only optical");
break;
case MediumTypes.WORM:
sb.AppendLine("a Write-once Read-many optical");
break;
case MediumTypes.Erasable:
sb.AppendLine("a Erasable optical");
break;
case MediumTypes.RO_WORM:
sb.AppendLine("a combination of read-only and write-once optical");
break;
case MediumTypes.RO_RW:
sb.AppendLine("a combination of read-only and erasable optical");
break;
case MediumTypes.WORM_RW:
sb.AppendLine("a combination of write-once and erasable optical");
break;
case MediumTypes.DOW:
sb.AppendLine("a direct-overwrite optical");
break;
2015-10-25 02:07:39 +00:00
default:
sb.AppendFormat("an unknown medium type 0x{0:X2}", header.Value.MediumType).AppendLine();
break;
}
}
2016-04-19 02:11:47 +01:00
if(header.Value.WriteProtected)
sb.AppendLine("\tMedium is write protected");
2016-04-19 02:11:47 +01:00
if(header.Value.EBC)
sb.AppendLine("\tBlank checking during write is enabled");
2016-04-19 02:11:47 +01:00
if(header.Value.DPOFUA)
sb.AppendLine("\tDrive supports DPO and FUA bits");
2015-10-24 19:53:59 +01:00
2016-04-19 02:11:47 +01:00
if(header.Value.BlockDescriptors != null)
2015-10-24 19:53:59 +01:00
{
2016-04-19 02:11:47 +01:00
foreach(BlockDescriptor descriptor in header.Value.BlockDescriptors)
2015-10-24 19:53:59 +01:00
{
string density = "";
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
2015-10-24 19:53:59 +01:00
{
case DensityType.Default:
break;
case DensityType.ISO10090:
density = "ISO/IEC 10090: 86 mm Read/Write single-sided optical disc with 12500 tracks";
break;
case DensityType.D581:
density = "89 mm Read/Write double-sided optical disc with 12500 tracks";
break;
case DensityType.X3_212:
density = "ANSI X3.212: 130 mm Read/Write double-sided optical disc with 18750 tracks";
break;
case DensityType.X3_191:
density = "ANSI X3.191: 130 mm Write-Once double-sided optical disc with 30000 tracks";
break;
case DensityType.X3_214:
density = "ANSI X3.214: 130 mm Write-Once double-sided optical disc with 20000 tracks";
break;
case DensityType.X3_211:
density = "ANSI X3.211: 130 mm Write-Once double-sided optical disc with 18750 tracks";
break;
case DensityType.D407:
density = "200 mm optical disc";
break;
case DensityType.ISO13614:
density = "ISO/IEC 13614: 300 mm double-sided optical disc";
break;
case DensityType.X3_200:
density = "ANSI X3.200: 356 mm double-sided optical disc with 56350 tracks";
break;
default:
density = String.Format("unknown density code 0x{0:X2}", descriptor.Density);
break;
2015-10-24 19:53:59 +01:00
}
2016-04-19 02:11:47 +01:00
if(density != "")
2015-10-24 19:53:59 +01:00
{
2016-04-19 02:11:47 +01:00
if(descriptor.Blocks == 0)
{
2016-04-19 02:11:47 +01:00
if(descriptor.BlockLength == 0)
sb.AppendFormat("\tAll remaining blocks are {0} and have a variable length", density).AppendLine();
else
sb.AppendFormat("\tAll remaining blocks are {0} and are {1} bytes each", density, descriptor.BlockLength).AppendLine();
}
2015-10-24 19:53:59 +01:00
else
{
2016-04-19 02:11:47 +01:00
if(descriptor.BlockLength == 0)
sb.AppendFormat("\t{0} blocks are {1} and have a variable length", descriptor.Blocks, density).AppendLine();
else
sb.AppendFormat("\t{0} blocks are {1} and are {2} bytes each", descriptor.Blocks, density, descriptor.BlockLength).AppendLine();
}
2015-10-24 19:53:59 +01:00
}
else
{
2016-04-19 02:11:47 +01:00
if(descriptor.Blocks == 0)
{
2016-04-19 02:11:47 +01:00
if(descriptor.BlockLength == 0)
sb.AppendFormat("\tAll remaining blocks have a variable length").AppendLine();
else
sb.AppendFormat("\tAll remaining blocks are {0} bytes each", descriptor.BlockLength).AppendLine();
}
2015-10-24 19:53:59 +01:00
else
{
2016-04-19 02:11:47 +01:00
if(descriptor.BlockLength == 0)
sb.AppendFormat("\t{0} blocks have a variable length", descriptor.Blocks).AppendLine();
else
sb.AppendFormat("\t{0} blocks are {1} bytes each", descriptor.Blocks, descriptor.BlockLength).AppendLine();
}
2015-10-24 19:53:59 +01:00
}
}
}
break;
}
2016-04-19 02:11:47 +01:00
#endregion Optical device mode header
#region Multimedia device mode header
2015-10-24 19:53:59 +01:00
case PeripheralDeviceTypes.MultiMediaDevice:
{
sb.Append("\tMedium is ");
2015-10-24 19:53:59 +01:00
2016-04-19 02:11:47 +01:00
switch(header.Value.MediumType)
2015-10-24 19:53:59 +01:00
{
case MediumTypes.CDROM:
sb.AppendLine("120 mm CD-ROM");
break;
case MediumTypes.CDDA:
sb.AppendLine("120 mm Compact Disc Digital Audio");
break;
case MediumTypes.MixedCD:
sb.AppendLine("120 mm Compact Disc with data and audio");
break;
case MediumTypes.CDROM_80:
sb.AppendLine("80 mm CD-ROM");
break;
case MediumTypes.CDDA_80:
sb.AppendLine("80 mm Compact Disc Digital Audio");
break;
case MediumTypes.MixedCD_80:
sb.AppendLine("80 mm Compact Disc with data and audio");
break;
2015-10-30 19:03:40 +00:00
case MediumTypes.Unknown_CD:
sb.AppendLine("Unknown medium type");
break;
case MediumTypes.HybridCD:
sb.AppendLine("120 mm Hybrid disc (Photo CD)");
break;
case MediumTypes.Unknown_CDR:
sb.AppendLine("Unknown size CD-R");
break;
case MediumTypes.CDR:
sb.AppendLine("120 mm CD-R with data only");
break;
case MediumTypes.CDR_DA:
sb.AppendLine("120 mm CD-R with audio only");
break;
case MediumTypes.CDR_Mixed:
sb.AppendLine("120 mm CD-R with data and audio");
break;
case MediumTypes.HybridCDR:
sb.AppendLine("120 mm Hybrid CD-R (Photo CD)");
break;
case MediumTypes.CDR_80:
sb.AppendLine("80 mm CD-R with data only");
break;
case MediumTypes.CDR_DA_80:
sb.AppendLine("80 mm CD-R with audio only");
break;
case MediumTypes.CDR_Mixed_80:
sb.AppendLine("80 mm CD-R with data and audio");
break;
case MediumTypes.HybridCDR_80:
sb.AppendLine("80 mm Hybrid CD-R (Photo CD)");
break;
case MediumTypes.Unknown_CDRW:
sb.AppendLine("Unknown size CD-RW");
break;
case MediumTypes.CDRW:
sb.AppendLine("120 mm CD-RW with data only");
break;
case MediumTypes.CDRW_DA:
sb.AppendLine("120 mm CD-RW with audio only");
break;
case MediumTypes.CDRW_Mixed:
sb.AppendLine("120 mm CD-RW with data and audio");
break;
case MediumTypes.HybridCDRW:
sb.AppendLine("120 mm Hybrid CD-RW (Photo CD)");
break;
case MediumTypes.CDRW_80:
sb.AppendLine("80 mm CD-RW with data only");
break;
case MediumTypes.CDRW_DA_80:
sb.AppendLine("80 mm CD-RW with audio only");
break;
case MediumTypes.CDRW_Mixed_80:
sb.AppendLine("80 mm CD-RW with data and audio");
break;
case MediumTypes.HybridCDRW_80:
sb.AppendLine("80 mm Hybrid CD-RW (Photo CD)");
break;
case MediumTypes.Unknown_HD:
sb.AppendLine("Unknown size HD disc");
break;
case MediumTypes.HD:
sb.AppendLine("120 mm HD disc");
break;
case MediumTypes.HD_80:
sb.AppendLine("80 mm HD disc");
break;
case MediumTypes.NoDisc:
sb.AppendLine("No disc inserted, tray closed or caddy inserted");
break;
case MediumTypes.TrayOpen:
sb.AppendLine("Tray open or no caddy inserted");
break;
case MediumTypes.MediumError:
sb.AppendLine("Tray closed or caddy inserted but medium error");
break;
2015-10-31 05:28:06 +00:00
case MediumTypes.UnknownBlockDevice:
sb.AppendLine("Unknown block device");
break;
case MediumTypes.ReadOnlyBlockDevice:
sb.AppendLine("Read-only block device");
break;
case MediumTypes.ReadWriteBlockDevice:
sb.AppendLine("Read/Write block device");
break;
case MediumTypes.LTOCD:
sb.AppendLine("LTO in CD-ROM emulation mode");
break;
2015-10-24 19:53:59 +01:00
default:
sb.AppendFormat("Unknown medium type 0x{0:X2}", header.Value.MediumType).AppendLine();
break;
}
2016-04-19 02:11:47 +01:00
if(header.Value.WriteProtected)
sb.AppendLine("\tMedium is write protected");
2015-10-24 19:53:59 +01:00
2016-04-19 02:11:47 +01:00
if(header.Value.DPOFUA)
sb.AppendLine("\tDrive supports DPO and FUA bits");
2015-10-24 19:53:59 +01:00
2016-04-19 02:11:47 +01:00
if(header.Value.BlockDescriptors != null)
2015-10-24 19:53:59 +01:00
{
2016-04-19 02:11:47 +01:00
foreach(BlockDescriptor descriptor in header.Value.BlockDescriptors)
2015-10-24 19:53:59 +01:00
{
string density = "";
2016-04-19 02:11:47 +01:00
switch(descriptor.Density)
{
case DensityType.Default:
break;
case DensityType.User:
density = "user data only";
break;
case DensityType.UserAuxiliary:
density = "user data plus auxiliary data";
break;
case DensityType.UserAuxiliaryTag:
density = "4-byte tag, user data plus auxiliary data";
break;
case DensityType.Audio:
density = "audio information only";
break;
case DensityType.LTO2:
density = "LTO Ultrium-2";
break;
case DensityType.LTO3:
density = "LTO Ultrium-3";
break;
case DensityType.LTO4:
density = "LTO Ultrium-4";
break;
case DensityType.LTO5:
density = "LTO Ultrium-5";
break;
default:
density = String.Format("with unknown density code 0x{0:X2}", descriptor.Density);
break;
}
2015-10-24 19:53:59 +01:00
2016-04-19 02:11:47 +01:00
if(density != "")
{
2016-04-19 02:11:47 +01:00
if(descriptor.Blocks == 0)
sb.AppendFormat("\tAll remaining blocks have {0} and are {1} bytes each", density, descriptor.BlockLength).AppendLine();
else
sb.AppendFormat("\t{0} blocks have {1} and are {2} bytes each", descriptor.Blocks, density, descriptor.BlockLength).AppendLine();
}
2015-10-24 19:53:59 +01:00
else
{
2016-04-19 02:11:47 +01:00
if(descriptor.Blocks == 0)
sb.AppendFormat("\tAll remaining blocks are {0} bytes each", descriptor.BlockLength).AppendLine();
else
sb.AppendFormat("\t{0} blocks are {1} bytes each", descriptor.Blocks, descriptor.BlockLength).AppendLine();
}
2015-10-24 19:53:59 +01:00
}
}
2015-10-24 06:58:49 +01:00
break;
}
2016-04-19 02:11:47 +01:00
#endregion Multimedia device mode header
2015-10-24 06:58:49 +01:00
default:
break;
}
return sb.ToString();
}
public static ModeHeader? DecodeModeHeader10(byte[] modeResponse, PeripheralDeviceTypes deviceType)
{
2016-04-19 02:11:47 +01:00
if(modeResponse == null || modeResponse.Length < 8)
return null;
ushort modeLength;
ushort blockDescLength;
modeLength = (ushort)((modeResponse[0] << 8) + modeResponse[1]);
blockDescLength = (ushort)((modeResponse[6] << 8) + modeResponse[7]);
2016-04-19 02:11:47 +01:00
if(modeResponse.Length < modeLength)
return null;
ModeHeader header = new ModeHeader();
header.MediumType = (MediumTypes)modeResponse[2];
2015-10-31 18:50:15 +00:00
bool longLBA = (modeResponse[4] & 0x01) == 0x01;
2016-04-19 02:11:47 +01:00
if(blockDescLength > 0)
{
2016-04-19 02:11:47 +01:00
if(longLBA)
{
2015-10-31 18:50:15 +00:00
header.BlockDescriptors = new BlockDescriptor[blockDescLength / 16];
2016-04-19 02:11:47 +01:00
for(int i = 0; i < header.BlockDescriptors.Length; i++)
2015-10-31 18:50:15 +00:00
{
header.BlockDescriptors[i] = new BlockDescriptor();
header.BlockDescriptors[i].Density = DensityType.Default;
byte[] temp = new byte[8];
temp[0] = modeResponse[7 + i * 16 + 8];
temp[1] = modeResponse[6 + i * 16 + 8];
temp[2] = modeResponse[5 + i * 16 + 8];
temp[3] = modeResponse[4 + i * 16 + 8];
temp[4] = modeResponse[3 + i * 16 + 8];
temp[5] = modeResponse[2 + i * 16 + 8];
temp[6] = modeResponse[1 + i * 16 + 8];
temp[7] = modeResponse[0 + i * 16 + 8];
header.BlockDescriptors[i].Blocks = BitConverter.ToUInt64(temp, 0);
header.BlockDescriptors[i].BlockLength += (uint)(modeResponse[15 + i * 16 + 8] << 24);
header.BlockDescriptors[i].BlockLength += (uint)(modeResponse[14 + i * 16 + 8] << 16);
header.BlockDescriptors[i].BlockLength += (uint)(modeResponse[13 + i * 16 + 8] << 8);
header.BlockDescriptors[i].BlockLength += modeResponse[12 + i * 16 + 8];
}
}
else
{
header.BlockDescriptors = new BlockDescriptor[blockDescLength / 8];
2016-04-19 02:11:47 +01:00
for(int i = 0; i < header.BlockDescriptors.Length; i++)
2015-10-31 18:50:15 +00:00
{
header.BlockDescriptors[i] = new BlockDescriptor();
2016-04-19 02:11:47 +01:00
if(deviceType != PeripheralDeviceTypes.DirectAccess)
2015-10-31 18:50:15 +00:00
{
header.BlockDescriptors[i].Density = (DensityType)modeResponse[0 + i * 8 + 8];
}
else
{
header.BlockDescriptors[i].Density = DensityType.Default;
header.BlockDescriptors[i].Blocks += (ulong)(modeResponse[0 + i * 8 + 8] << 24);
}
header.BlockDescriptors[i].Blocks += (ulong)(modeResponse[1 + i * 8 + 8] << 16);
header.BlockDescriptors[i].Blocks += (ulong)(modeResponse[2 + i * 8 + 8] << 8);
header.BlockDescriptors[i].Blocks += modeResponse[3 + i * 8 + 8];
header.BlockDescriptors[i].BlockLength += (uint)(modeResponse[5 + i * 8 + 8] << 16);
header.BlockDescriptors[i].BlockLength += (uint)(modeResponse[6 + i * 8 + 8] << 8);
header.BlockDescriptors[i].BlockLength += modeResponse[7 + i * 8 + 8];
}
}
}
2016-04-19 02:11:47 +01:00
if(deviceType == PeripheralDeviceTypes.DirectAccess || deviceType == PeripheralDeviceTypes.MultiMediaDevice)
{
header.WriteProtected = ((modeResponse[3] & 0x80) == 0x80);
header.DPOFUA = ((modeResponse[3] & 0x10) == 0x10);
}
2016-04-19 02:11:47 +01:00
if(deviceType == PeripheralDeviceTypes.SequentialAccess)
{
header.WriteProtected = ((modeResponse[3] & 0x80) == 0x80);
header.Speed = (byte)(modeResponse[3] & 0x0F);
header.BufferedMode = (byte)((modeResponse[3] & 0x70) >> 4);
}
2016-04-19 02:11:47 +01:00
if(deviceType == PeripheralDeviceTypes.PrinterDevice)
header.BufferedMode = (byte)((modeResponse[3] & 0x70) >> 4);
2016-04-19 02:11:47 +01:00
if(deviceType == PeripheralDeviceTypes.OpticalDevice)
{
header.WriteProtected = ((modeResponse[3] & 0x80) == 0x80);
header.EBC = ((modeResponse[3] & 0x01) == 0x01);
header.DPOFUA = ((modeResponse[3] & 0x10) == 0x10);
}
return header;
}
public static string PrettifyModeHeader10(byte[] modeResponse, PeripheralDeviceTypes deviceType)
{
return PrettifyModeHeader(DecodeModeHeader10(modeResponse, deviceType), deviceType);
}
2015-10-25 05:39:25 +00:00
#region Mode Page 0x0A: Control mode page
2015-10-25 05:39:25 +00:00
/// <summary>
/// Control mode page
/// Page code 0x0A
/// 8 bytes in SCSI-2
2015-10-30 22:25:18 +00:00
/// 12 bytes in SPC-1, SPC-2, SPC-3, SPC-4, SPC-5
2015-10-25 05:39:25 +00:00
/// </summary>
public struct ModePage_0A
{
/// <summary>
/// Parameters can be saved
/// </summary>
public bool PS;
/// <summary>
/// If set, target shall report log exception conditions
/// </summary>
public bool RLEC;
/// <summary>
/// Queue algorithm modifier
/// </summary>
public byte QueueAlgorithm;
/// <summary>
/// If set all remaining suspended I/O processes shall be aborted after the contingent allegiance condition or extended contingent allegiance condition
/// </summary>
public byte QErr;
/// <summary>
/// Tagged queuing is disabled
/// </summary>
public bool DQue;
/// <summary>
/// Extended Contingent Allegiance is enabled
/// </summary>
public bool EECA;
/// <summary>
/// Target may issue an asynchronous event notification upon completing its initialization
/// </summary>
public bool RAENP;
/// <summary>
/// Target may issue an asynchronous event notification instead of a unit attention condition
/// </summary>
public bool UAAENP;
/// <summary>
/// Target may issue an asynchronous event notification instead of a deferred error
/// </summary>
public bool EAENP;
/// <summary>
/// Minimum time in ms after initialization before attempting asynchronous event notifications
/// </summary>
public ushort ReadyAENHoldOffPeriod;
/// <summary>
/// Global logging target save disabled
/// </summary>
public bool GLTSD;
/// <summary>
/// CHECK CONDITION should be reported rather than a long busy condition
/// </summary>
public bool RAC;
/// <summary>
/// Software write protect is active
/// </summary>
public bool SWP;
/// <summary>
/// Maximum time in 100 ms units allowed to remain busy. 0xFFFF == unlimited.
/// </summary>
public ushort BusyTimeoutPeriod;
/// <summary>
/// Task set type
/// </summary>
public byte TST;
/// <summary>
/// Tasks aborted by other initiator's actions should be terminated with TASK ABORTED
/// </summary>
public bool TAS;
/// <summary>
/// Action to be taken when a medium is inserted
/// </summary>
public byte AutoloadMode;
/// <summary>
/// Time in seconds to complete an extended self-test
/// </summary>
public byte ExtendedSelfTestCompletionTime;
/// <summary>
/// All tasks received in nexus with ACA ACTIVE is set and an ACA condition is established shall terminate
/// </summary>
public bool TMF_ONLY;
/// <summary>
/// Device shall return descriptor format sense data when returning sense data in the same transactions as a CHECK CONDITION
/// </summary>
public bool D_SENSE;
/// <summary>
/// Unit attention interlocks control
/// </summary>
public byte UA_INTLCK_CTRL;
/// <summary>
/// LOGICAL BLOCK APPLICATION TAG should not be modified
/// </summary>
public bool ATO;
/// <summary>
/// Protector information checking is disabled
/// </summary>
public bool DPICZ;
/// <summary>
/// No unit attention on release
/// </summary>
public bool NUAR;
/// <summary>
/// Application Tag mode page is enabled
/// </summary>
public bool ATMPE;
/// <summary>
/// Abort any write command without protection information
/// </summary>
public bool RWWP;
/// <summary>
/// Supportes block lengths and protection information
/// </summary>
public bool SBLP;
}
public static ModePage_0A? DecodeModePage_0A(byte[] pageResponse)
{
2016-04-19 02:11:47 +01:00
if(pageResponse == null)
2015-10-25 05:39:25 +00:00
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x40) == 0x40)
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x3F) != 0x0A)
2015-10-25 05:39:25 +00:00
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse[1] + 2 != pageResponse.Length)
2015-10-25 05:39:25 +00:00
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse.Length < 8)
2015-10-25 05:39:25 +00:00
return null;
ModePage_0A decoded = new ModePage_0A();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.RLEC |= (pageResponse[2] & 0x01) == 0x01;
decoded.QueueAlgorithm = (byte)((pageResponse[3] & 0xF0) >> 4);
decoded.QErr = (byte)((pageResponse[3] & 0x06) >> 1);
decoded.DQue |= (pageResponse[3] & 0x01) == 0x01;
decoded.EECA |= (pageResponse[4] & 0x80) == 0x80;
decoded.RAENP |= (pageResponse[4] & 0x04) == 0x04;
decoded.UAAENP |= (pageResponse[4] & 0x02) == 0x02;
decoded.EAENP |= (pageResponse[4] & 0x01) == 0x01;
decoded.ReadyAENHoldOffPeriod = (ushort)((pageResponse[6] << 8) + pageResponse[7]);
2016-04-19 02:11:47 +01:00
if(pageResponse.Length < 10)
2015-10-25 05:39:25 +00:00
return decoded;
// SPC-1
decoded.GLTSD |= (pageResponse[2] & 0x02) == 0x02;
decoded.RAC |= (pageResponse[4] & 0x40) == 0x40;
decoded.SWP |= (pageResponse[4] & 0x08) == 0x08;
decoded.BusyTimeoutPeriod = (ushort)((pageResponse[8] << 8) + pageResponse[9]);
// SPC-2
decoded.TST = (byte)((pageResponse[2] & 0xE0) >> 5);
decoded.TAS |= (pageResponse[4] & 0x80) == 0x80;
decoded.AutoloadMode = (byte)(pageResponse[5] & 0x07);
decoded.BusyTimeoutPeriod = (ushort)((pageResponse[10] << 8) + pageResponse[11]);
// SPC-3
decoded.TMF_ONLY |= (pageResponse[2] & 0x10) == 0x10;
decoded.D_SENSE |= (pageResponse[2] & 0x04) == 0x04;
decoded.UA_INTLCK_CTRL = (byte)((pageResponse[4] & 0x30) >> 4);
decoded.TAS |= (pageResponse[5] & 0x40) == 0x40;
decoded.ATO |= (pageResponse[5] & 0x80) == 0x80;
// SPC-5
decoded.DPICZ |= (pageResponse[2] & 0x08) == 0x08;
decoded.NUAR |= (pageResponse[3] & 0x08) == 0x08;
decoded.ATMPE |= (pageResponse[5] & 0x20) == 0x20;
decoded.RWWP |= (pageResponse[5] & 0x10) == 0x10;
decoded.SBLP |= (pageResponse[5] & 0x08) == 0x08;
return decoded;
}
public static string PrettifyModePage_0A(byte[] pageResponse)
{
return PrettifyModePage_0A(DecodeModePage_0A(pageResponse));
}
public static string PrettifyModePage_0A(ModePage_0A? modePage)
{
2016-04-19 02:11:47 +01:00
if(!modePage.HasValue)
2015-10-25 05:39:25 +00:00
return null;
ModePage_0A page = modePage.Value;
StringBuilder sb = new StringBuilder();
sb.AppendLine("SCSI Control mode page:");
2016-04-19 02:11:47 +01:00
if(page.PS)
2015-10-25 05:39:25 +00:00
sb.AppendLine("\tParameters can be saved");
2016-04-19 02:11:47 +01:00
if(page.RLEC)
2015-10-25 05:39:25 +00:00
sb.AppendLine("\tIf set, target shall report log exception conditions");
2016-04-19 02:11:47 +01:00
if(page.DQue)
2015-10-25 05:39:25 +00:00
sb.AppendLine("\tTagged queuing is disabled");
2016-04-19 02:11:47 +01:00
if(page.EECA)
2015-10-25 05:39:25 +00:00
sb.AppendLine("\tExtended Contingent Allegiance is enabled");
2016-04-19 02:11:47 +01:00
if(page.RAENP)
2015-10-25 05:39:25 +00:00
sb.AppendLine("\tTarget may issue an asynchronous event notification upon completing its initialization");
2016-04-19 02:11:47 +01:00
if(page.UAAENP)
2015-10-25 05:39:25 +00:00
sb.AppendLine("\tTarget may issue an asynchronous event notification instead of a unit attention condition");
2016-04-19 02:11:47 +01:00
if(page.EAENP)
2015-10-25 05:39:25 +00:00
sb.AppendLine("\tTarget may issue an asynchronous event notification instead of a deferred error");
2016-04-19 02:11:47 +01:00
if(page.GLTSD)
2015-10-25 05:39:25 +00:00
sb.AppendLine("\tGlobal logging target save disabled");
2016-04-19 02:11:47 +01:00
if(page.RAC)
2015-10-25 05:39:25 +00:00
sb.AppendLine("\tCHECK CONDITION should be reported rather than a long busy condition");
2016-04-19 02:11:47 +01:00
if(page.SWP)
2015-10-25 05:39:25 +00:00
sb.AppendLine("\tSoftware write protect is active");
2016-04-19 02:11:47 +01:00
if(page.TAS)
2015-10-25 05:39:25 +00:00
sb.AppendLine("\tTasks aborted by other initiator's actions should be terminated with TASK ABORTED");
2016-04-19 02:11:47 +01:00
if(page.TMF_ONLY)
2015-10-25 05:39:25 +00:00
sb.AppendLine("\tAll tasks received in nexus with ACA ACTIVE is set and an ACA condition is established shall terminate");
2016-04-19 02:11:47 +01:00
if(page.D_SENSE)
2015-10-25 05:39:25 +00:00
sb.AppendLine("\tDevice shall return descriptor format sense data when returning sense data in the same transactions as a CHECK CONDITION");
2016-04-19 02:11:47 +01:00
if(page.ATO)
2015-10-25 05:39:25 +00:00
sb.AppendLine("\tLOGICAL BLOCK APPLICATION TAG should not be modified");
2016-04-19 02:11:47 +01:00
if(page.DPICZ)
2015-10-25 05:39:25 +00:00
sb.AppendLine("\tProtector information checking is disabled");
2016-04-19 02:11:47 +01:00
if(page.NUAR)
2015-10-25 05:39:25 +00:00
sb.AppendLine("\tNo unit attention on release");
2016-04-19 02:11:47 +01:00
if(page.ATMPE)
2015-10-25 05:39:25 +00:00
sb.AppendLine("\tApplication Tag mode page is enabled");
2016-04-19 02:11:47 +01:00
if(page.RWWP)
2015-10-25 05:39:25 +00:00
sb.AppendLine("\tAbort any write command without protection information");
2016-04-19 02:11:47 +01:00
if(page.SBLP)
2015-10-25 05:39:25 +00:00
sb.AppendLine("\tSupportes block lengths and protection information");
2016-04-19 02:11:47 +01:00
switch(page.TST)
2015-10-25 05:39:25 +00:00
{
case 0:
sb.AppendLine("\tThe logical unit maintains one task set for all nexuses");
break;
case 1:
sb.AppendLine("\tThe logical unit maintains separate task sets for each nexus");
break;
default:
sb.AppendFormat("\tUnknown Task set type {0}", page.TST).AppendLine();
break;
}
2016-04-19 02:11:47 +01:00
switch(page.QueueAlgorithm)
2015-10-25 05:39:25 +00:00
{
case 0:
sb.AppendLine("\tCommands should be sent strictly ordered");
break;
case 1:
sb.AppendLine("\tCommands can be reordered in any manner");
break;
default:
sb.AppendFormat("\tUnknown Queue Algorithm Modifier {0}", page.QueueAlgorithm).AppendLine();
break;
}
2016-04-19 02:11:47 +01:00
switch(page.QErr)
2015-10-25 05:39:25 +00:00
{
case 0:
sb.AppendLine("\tIf ACA is established, the task set commands shall resume after it is cleared, otherwise they shall terminate with CHECK CONDITION");
break;
case 1:
sb.AppendLine("\tAll the affected commands in the task set shall be aborted when CHECK CONDITION is returned");
break;
case 3:
sb.AppendLine("\tAffected commands in the task set belonging with the CHECK CONDITION nexus shall be aborted");
break;
default:
sb.AppendLine("\tReserved QErr value 2 is set");
break;
}
2016-04-19 02:11:47 +01:00
switch(page.UA_INTLCK_CTRL)
2015-10-25 05:39:25 +00:00
{
case 0:
sb.AppendLine("\tLUN shall clear unit attention condition reported in the same nexus");
break;
case 2:
sb.AppendLine("\tLUN shall not clear unit attention condition reported in the same nexus");
break;
case 3:
sb.AppendLine("\tLUN shall not clear unit attention condition reported in the same nexus and shall establish a unit attention condition for the initiator");
break;
default:
sb.AppendLine("\tReserved UA_INTLCK_CTRL value 1 is set");
break;
}
2016-04-19 02:11:47 +01:00
switch(page.AutoloadMode)
2015-10-25 05:39:25 +00:00
{
case 0:
sb.AppendLine("\tOn medium insertion, it shall be loaded for full access");
break;
case 1:
sb.AppendLine("\tOn medium insertion, it shall be loaded for auxiliary memory access only");
break;
case 2:
sb.AppendLine("\tOn medium insertion, it shall not be loaded");
break;
default:
sb.AppendFormat("\tReserved autoload mode {0} set", page.AutoloadMode).AppendLine();
break;
}
2016-04-19 02:11:47 +01:00
if(page.ReadyAENHoldOffPeriod > 0)
2015-10-25 05:39:25 +00:00
sb.AppendFormat("\t{0} ms before attempting asynchronous event notifications after initialization", page.ReadyAENHoldOffPeriod).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.BusyTimeoutPeriod > 0)
2015-10-25 05:39:25 +00:00
{
2016-04-19 02:11:47 +01:00
if(page.BusyTimeoutPeriod == 0xFFFF)
2015-10-25 05:39:25 +00:00
sb.AppendLine("\tThere is no limit on the maximum time that is allowed to remain busy");
else
sb.AppendFormat("\tA maximum of {0} ms are allowed to remain busy", (int)page.BusyTimeoutPeriod * 100).AppendLine();
}
2016-04-19 02:11:47 +01:00
if(page.ExtendedSelfTestCompletionTime > 0)
2015-10-25 05:39:25 +00:00
sb.AppendFormat("\t{0} seconds to complete extended self-test", page.ExtendedSelfTestCompletionTime);
return sb.ToString();
}
2015-10-25 06:22:59 +00:00
#endregion Mode Page 0x0A: Control mode page
#region Mode Page 0x02: Disconnect-reconnect page
2015-10-25 06:22:59 +00:00
/// <summary>
/// Disconnect-reconnect page
/// Page code 0x02
2015-10-30 22:25:18 +00:00
/// 16 bytes in SCSI-2, SPC-1, SPC-2, SPC-3, SPC-4, SPC-5
2015-10-25 06:22:59 +00:00
/// </summary>
public struct ModePage_02
{
/// <summary>
/// Parameters can be saved
/// </summary>
public bool PS;
/// <summary>
/// How full should be the buffer prior to attempting a reselection
/// </summary>
public byte BufferFullRatio;
/// <summary>
/// How empty should be the buffer prior to attempting a reselection
/// </summary>
public byte BufferEmptyRatio;
/// <summary>
/// Max. time in 100 µs increments that the target is permitted to assert BSY without a REQ/ACK
/// </summary>
public ushort BusInactivityLimit;
/// <summary>
/// Min. time in 100 µs increments to wait after releasing the bus before attempting reselection
/// </summary>
public ushort DisconnectTimeLimit;
/// <summary>
/// Max. time in 100 µs increments allowed to use the bus before disconnecting, if granted the privilege and not restricted by <see cref="DTDC"/>
/// </summary>
public ushort ConnectTimeLimit;
/// <summary>
/// Maximum amount of data before disconnecting in 512 bytes increments
/// </summary>
public ushort MaxBurstSize;
/// <summary>
/// Data transfer disconnect control
/// </summary>
public byte DTDC;
/// <summary>
/// Target shall not transfer data for a command during the same interconnect tenancy
/// </summary>
public bool DIMM;
/// <summary>
/// Wether to use fair or unfair arbitration when requesting an interconnect tenancy
/// </summary>
public byte FairArbitration;
/// <summary>
/// Max. ammount of data in 512 bytes increments that may be transferred for a command along with the command
/// </summary>
public ushort FirstBurstSize;
/// <summary>
/// Target is allowed to re-order the data transfer
/// </summary>
public bool EMDP;
}
public static ModePage_02? DecodeModePage_02(byte[] pageResponse)
{
2016-04-19 02:11:47 +01:00
if(pageResponse == null)
2015-10-25 06:22:59 +00:00
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x40) == 0x40)
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x3F) != 0x02)
2015-10-25 06:22:59 +00:00
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse[1] + 2 != pageResponse.Length)
2015-10-25 06:22:59 +00:00
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse.Length < 16)
2015-10-25 06:22:59 +00:00
return null;
ModePage_02 decoded = new ModePage_02();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.BufferFullRatio = pageResponse[2];
decoded.BufferEmptyRatio = pageResponse[3];
decoded.BusInactivityLimit = (ushort)((pageResponse[4] << 8) + pageResponse[5]);
decoded.DisconnectTimeLimit = (ushort)((pageResponse[6] << 8) + pageResponse[7]);
decoded.ConnectTimeLimit = (ushort)((pageResponse[8] << 8) + pageResponse[9]);
decoded.MaxBurstSize = (ushort)((pageResponse[10] << 8) + pageResponse[11]);
decoded.FirstBurstSize = (ushort)((pageResponse[14] << 8) + pageResponse[15]);
decoded.EMDP |= (pageResponse[12] & 0x80) == 0x80;
decoded.DIMM |= (pageResponse[12] & 0x08) == 0x08;
decoded.FairArbitration = (byte)((pageResponse[12] & 0x70) >> 4);
decoded.DTDC = (byte)(pageResponse[12] & 0x07);
return decoded;
}
public static string PrettifyModePage_02(byte[] pageResponse)
{
return PrettifyModePage_02(DecodeModePage_02(pageResponse));
}
public static string PrettifyModePage_02(ModePage_02? modePage)
{
2016-04-19 02:11:47 +01:00
if(!modePage.HasValue)
2015-10-25 06:22:59 +00:00
return null;
ModePage_02 page = modePage.Value;
StringBuilder sb = new StringBuilder();
sb.AppendLine("SCSI Disconnect-Reconnect mode page:");
2016-04-19 02:11:47 +01:00
if(page.PS)
2015-10-25 06:22:59 +00:00
sb.AppendLine("\tParameters can be saved");
2016-04-19 02:11:47 +01:00
if(page.BufferFullRatio > 0)
2015-10-25 06:22:59 +00:00
sb.AppendFormat("\t{0} ratio of buffer that shall be full prior to attempting a reselection", page.BufferFullRatio).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.BufferEmptyRatio > 0)
2015-10-25 06:22:59 +00:00
sb.AppendFormat("\t{0} ratio of buffer that shall be empty prior to attempting a reselection", page.BufferEmptyRatio).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.BusInactivityLimit > 0)
2015-10-25 06:22:59 +00:00
sb.AppendFormat("\t{0} µs maximum permitted to assert BSY without a REQ/ACK handshake", (int)page.BusInactivityLimit * 100).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.DisconnectTimeLimit > 0)
2015-10-25 06:22:59 +00:00
sb.AppendFormat("\t{0} µs maximum permitted wait after releasing the bus before attempting reselection", (int)page.DisconnectTimeLimit * 100).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.ConnectTimeLimit > 0)
2015-10-25 06:22:59 +00:00
sb.AppendFormat("\t{0} µs allowed to use the bus before disconnecting, if granted the privilege and not restricted", (int)page.ConnectTimeLimit * 100).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.MaxBurstSize > 0)
2015-10-25 06:22:59 +00:00
sb.AppendFormat("\t{0} bytes maximum can be transferred before disconnecting", (int)page.MaxBurstSize * 512).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.FirstBurstSize > 0)
2015-10-25 06:22:59 +00:00
sb.AppendFormat("\t{0} bytes maximum can be transferred for a command along with the disconnect command", (int)page.FirstBurstSize * 512).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.DIMM)
2015-10-25 06:22:59 +00:00
sb.AppendLine("\tTarget shall not transfer data for a command during the same interconnect tenancy");
2016-04-19 02:11:47 +01:00
if(page.EMDP)
2015-10-25 06:22:59 +00:00
sb.AppendLine("\tTarget is allowed to re-order the data transfer");
2016-04-19 02:11:47 +01:00
switch(page.DTDC)
2015-10-25 06:22:59 +00:00
{
case 0:
sb.AppendLine("\tData transfer disconnect control is not used");
break;
case 1:
sb.AppendLine("\tAll data for a command shall be transferred within a single interconnect tenancy");
break;
case 3:
sb.AppendLine("\tAll data and the response for a command shall be transferred within a single interconnect tenancy");
break;
default:
sb.AppendFormat("\tReserved data transfer disconnect control value {0}", page.DTDC).AppendLine();
break;
}
return sb.ToString();
}
2015-10-25 06:22:59 +00:00
#endregion Mode Page 0x02: Disconnect-reconnect page
2015-10-29 04:21:18 +00:00
#region Mode Page 0x08: Caching page
2015-10-29 04:21:18 +00:00
/// <summary>
/// Disconnect-reconnect page
/// Page code 0x08
/// 12 bytes in SCSI-2
2015-10-31 01:38:27 +00:00
/// 20 bytes in SBC-1, SBC-2, SBC-3
2015-10-29 04:21:18 +00:00
/// </summary>
public struct ModePage_08
{
/// <summary>
/// Parameters can be saved
/// </summary>
public bool PS;
/// <summary>
/// <c>true</c> if write cache is enabled
/// </summary>
public bool WCE;
/// <summary>
/// Multiplication factor
/// </summary>
public bool MF;
/// <summary>
/// <c>true</c> if read cache is enabled
/// </summary>
public bool RCD;
/// <summary>
/// Advices on reading-cache retention priority
/// </summary>
public byte DemandReadRetentionPrio;
/// <summary>
/// Advices on writing-cache retention priority
/// </summary>
public byte WriteRetentionPriority;
/// <summary>
/// If requested read blocks are more than this, no pre-fetch is done
/// </summary>
public ushort DisablePreFetch;
/// <summary>
/// Minimum pre-fetch
/// </summary>
public ushort MinimumPreFetch;
/// <summary>
/// Maximum pre-fetch
/// </summary>
public ushort MaximumPreFetch;
/// <summary>
/// Upper limit on maximum pre-fetch value
/// </summary>
public ushort MaximumPreFetchCeiling;
/// <summary>
/// Manual cache controlling
/// </summary>
public bool IC;
/// <summary>
/// Abort pre-fetch
/// </summary>
public bool ABPF;
/// <summary>
/// Caching analysis permitted
/// </summary>
public bool CAP;
/// <summary>
/// Pre-fetch over discontinuities
/// </summary>
public bool Disc;
/// <summary>
/// <see cref="CacheSegmentSize"/> is to be used to control caching segmentation
/// </summary>
public bool Size;
/// <summary>
/// Force sequential write
/// </summary>
public bool FSW;
/// <summary>
/// Logical block cache segment size
/// </summary>
public bool LBCSS;
/// <summary>
/// Disable read-ahead
/// </summary>
public bool DRA;
/// <summary>
/// How many segments should the cache be divided upon
/// </summary>
public byte CacheSegments;
/// <summary>
/// How many bytes should the cache be divided upon
/// </summary>
public ushort CacheSegmentSize;
/// <summary>
/// How many bytes should be used as a buffer when all other cached data cannot be evicted
/// </summary>
public uint NonCacheSegmentSize;
2015-10-31 01:31:51 +00:00
public bool NV_DIS;
2015-10-29 04:21:18 +00:00
}
public static ModePage_08? DecodeModePage_08(byte[] pageResponse)
{
2016-04-19 02:11:47 +01:00
if(pageResponse == null)
2015-10-29 04:21:18 +00:00
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x40) == 0x40)
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x3F) != 0x08)
2015-10-29 04:21:18 +00:00
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse[1] + 2 != pageResponse.Length)
2015-10-29 04:21:18 +00:00
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse.Length < 12)
2015-10-29 04:21:18 +00:00
return null;
ModePage_08 decoded = new ModePage_08();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.WCE |= (pageResponse[2] & 0x04) == 0x04;
decoded.MF |= (pageResponse[2] & 0x02) == 0x02;
decoded.RCD |= (pageResponse[2] & 0x01) == 0x01;
decoded.DemandReadRetentionPrio = (byte)((pageResponse[3] & 0xF0) >> 4);
decoded.WriteRetentionPriority = (byte)(pageResponse[3] & 0x0F);
decoded.DisablePreFetch = (ushort)((pageResponse[4] << 8) + pageResponse[5]);
decoded.MinimumPreFetch = (ushort)((pageResponse[6] << 8) + pageResponse[7]);
decoded.MaximumPreFetch = (ushort)((pageResponse[8] << 8) + pageResponse[9]);
decoded.MaximumPreFetchCeiling = (ushort)((pageResponse[10] << 8) + pageResponse[11]);
2016-04-19 02:11:47 +01:00
if(pageResponse.Length < 20)
return decoded;
decoded.IC |= (pageResponse[2] & 0x80) == 0x80;
decoded.ABPF |= (pageResponse[2] & 0x40) == 0x40;
decoded.CAP |= (pageResponse[2] & 0x20) == 0x20;
decoded.Disc |= (pageResponse[2] & 0x10) == 0x10;
decoded.Size |= (pageResponse[2] & 0x08) == 0x08;
decoded.FSW |= (pageResponse[12] & 0x80) == 0x80;
decoded.LBCSS |= (pageResponse[12] & 0x40) == 0x40;
decoded.DRA |= (pageResponse[12] & 0x20) == 0x20;
decoded.CacheSegments = pageResponse[13];
decoded.CacheSegmentSize = (ushort)((pageResponse[14] << 8) + pageResponse[15]);
decoded.NonCacheSegmentSize = (uint)((pageResponse[17] << 16) + (pageResponse[18] << 8) + pageResponse[19]);
2015-10-31 01:31:51 +00:00
decoded.NV_DIS |= (pageResponse[12] & 0x01) == 0x01;
2015-10-29 04:21:18 +00:00
return decoded;
}
public static string PrettifyModePage_08(byte[] pageResponse)
{
return PrettifyModePage_08(DecodeModePage_08(pageResponse));
}
public static string PrettifyModePage_08(ModePage_08? modePage)
{
2016-04-19 02:11:47 +01:00
if(!modePage.HasValue)
2015-10-29 04:21:18 +00:00
return null;
ModePage_08 page = modePage.Value;
StringBuilder sb = new StringBuilder();
sb.AppendLine("SCSI Caching mode page:");
2016-04-19 02:11:47 +01:00
if(page.PS)
2015-10-29 04:21:18 +00:00
sb.AppendLine("\tParameters can be saved");
2016-04-19 02:11:47 +01:00
if(page.RCD)
2015-10-29 04:21:18 +00:00
sb.AppendLine("\tRead-cache is enabled");
2016-04-19 02:11:47 +01:00
if(page.WCE)
2015-10-29 04:21:18 +00:00
sb.AppendLine("\tWrite-cache is enabled");
2016-04-19 02:11:47 +01:00
switch(page.DemandReadRetentionPrio)
2015-10-29 04:21:18 +00:00
{
case 0:
sb.AppendLine("\tDrive does not distinguish between cached read data");
break;
case 1:
sb.AppendLine("\tData put by READ commands should be evicted from cache sooner than data put in read cache by other means");
break;
case 0xF:
sb.AppendLine("\tData put by READ commands should not be evicted if there is data cached by other means that can be evicted");
break;
default:
sb.AppendFormat("\tUnknown demand read retention priority value {0}", page.DemandReadRetentionPrio).AppendLine();
break;
}
2016-04-19 02:11:47 +01:00
switch(page.WriteRetentionPriority)
2015-10-29 04:21:18 +00:00
{
case 0:
sb.AppendLine("\tDrive does not distinguish between cached write data");
break;
case 1:
sb.AppendLine("\tData put by WRITE commands should be evicted from cache sooner than data put in write cache by other means");
break;
case 0xF:
sb.AppendLine("\tData put by WRITE commands should not be evicted if there is data cached by other means that can be evicted");
break;
default:
sb.AppendFormat("\tUnknown demand write retention priority value {0}", page.DemandReadRetentionPrio).AppendLine();
break;
}
2016-04-19 02:11:47 +01:00
if(page.DRA)
sb.AppendLine("\tRead-ahead is disabled");
else
{
2016-04-19 02:11:47 +01:00
if(page.MF)
sb.AppendLine("\tPre-fetch values indicate a block multiplier");
2016-04-19 02:11:47 +01:00
if(page.DisablePreFetch == 0)
sb.AppendLine("\tNo pre-fetch will be done");
else
{
sb.AppendFormat("\tPre-fetch will be done for READ commands of {0} blocks or less", page.DisablePreFetch).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.MinimumPreFetch > 0)
sb.AppendFormat("At least {0} blocks will be always pre-fetched", page.MinimumPreFetch).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.MaximumPreFetch > 0)
sb.AppendFormat("\tA maximum of {0} blocks will be pre-fetched", page.MaximumPreFetch).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.MaximumPreFetchCeiling > 0)
sb.AppendFormat("\tA maximum of {0} blocks will be pre-fetched even if it is commanded to pre-fetch more", page.MaximumPreFetchCeiling).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.IC)
sb.AppendLine("\tDevice should use number of cache segments or cache segment size for caching");
2016-04-19 02:11:47 +01:00
if(page.ABPF)
sb.AppendLine("\tPre-fetch should be aborted upong receiving a new command");
2016-04-19 02:11:47 +01:00
if(page.CAP)
sb.AppendLine("\tCaching analysis is permitted");
2016-04-19 02:11:47 +01:00
if(page.Disc)
sb.AppendLine("\tPre-fetch can continue across discontinuities (such as cylinders or tracks)");
}
}
2016-04-19 02:11:47 +01:00
if(page.FSW)
sb.AppendLine("\tDrive should not reorder the sequence of write commands to be faster");
2015-10-29 04:21:18 +00:00
2016-04-19 02:11:47 +01:00
if(page.Size)
{
2016-04-19 02:11:47 +01:00
if(page.CacheSegmentSize > 0)
{
2016-04-19 02:11:47 +01:00
if(page.LBCSS)
sb.AppendFormat("\tDrive cache segments should be {0} blocks long", page.CacheSegmentSize).AppendLine();
else
sb.AppendFormat("\tDrive cache segments should be {0} bytes long", page.CacheSegmentSize).AppendLine();
}
}
2015-10-29 04:21:18 +00:00
else
{
2016-04-19 02:11:47 +01:00
if(page.CacheSegments > 0)
sb.AppendFormat("\tDrive should have {0} cache segments", page.CacheSegments).AppendLine();
2015-10-29 04:21:18 +00:00
}
2016-04-19 02:11:47 +01:00
if(page.NonCacheSegmentSize > 0)
sb.AppendFormat("\tDrive shall allocate {0} bytes to buffer even when all cached data cannot be evicted", page.NonCacheSegmentSize).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.NV_DIS)
2015-10-31 01:31:51 +00:00
sb.AppendLine("\tNon-Volatile cache is disabled");
2015-10-29 04:21:18 +00:00
return sb.ToString();
}
2015-10-29 04:21:18 +00:00
#endregion Mode Page 0x08: Caching page
2015-10-29 05:15:27 +00:00
#region Mode Page 0x05: Flexible disk page
2015-10-29 05:15:27 +00:00
/// <summary>
/// Disconnect-reconnect page
/// Page code 0x05
/// 32 bytes in SCSI-2, SBC-1
2015-10-29 05:15:27 +00:00
/// </summary>
public struct ModePage_05
{
/// <summary>
/// Parameters can be saved
/// </summary>
public bool PS;
/// <summary>
/// Data rate of peripheral device on kbit/s
/// </summary>
public ushort TransferRate;
/// <summary>
/// Heads for reading and/or writing
/// </summary>
public byte Heads;
/// <summary>
/// Sectors per revolution per head
/// </summary>
public byte SectorsPerTrack;
/// <summary>
/// Bytes of data per sector
/// </summary>
public ushort BytesPerSector;
/// <summary>
/// Cylinders used for data storage
/// </summary>
public ushort Cylinders;
/// <summary>
/// Cylinder where write precompensation starts
/// </summary>
public ushort WritePrecompCylinder;
/// <summary>
/// Cylinder where write current reduction starts
/// </summary>
public ushort WriteReduceCylinder;
/// <summary>
/// Step rate in 100 μs units
/// </summary>
public ushort DriveStepRate;
/// <summary>
/// Width of step pulse in μs
/// </summary>
public byte DriveStepPulse;
/// <summary>
/// Head settle time in 100 μs units
/// </summary>
public ushort HeadSettleDelay;
/// <summary>
/// If <see cref="TRDY"/> is <c>true</c>, specified in 1/10s of a
/// second the time waiting for read status before aborting medium
/// access. Otherwise, indicates time to way before medimum access
/// after motor on signal is asserted.
/// </summary>
public byte MotorOnDelay;
/// <summary>
/// Time in 1/10s of a second to wait before releasing the motor on
/// signal after an idle condition. 0xFF means to never release the
/// signal
/// </summary>
public byte MotorOffDelay;
/// <summary>
/// Specifies if a signal indicates that the medium is ready to be accessed
/// </summary>
public bool TRDY;
/// <summary>
/// If <c>true</c> sectors start with one. Otherwise, they start with zero.
/// </summary>
public bool SSN;
/// <summary>
/// If <c>true</c> specifies that motor on shall remain released.
/// </summary>
public bool MO;
/// <summary>
/// Number of additional step pulses per cylinder.
/// </summary>
public byte SPC;
/// <summary>
/// Write compensation value
/// </summary>
public byte WriteCompensation;
/// <summary>
/// Head loading time in ms.
/// </summary>
public byte HeadLoadDelay;
/// <summary>
/// Head unloading time in ms.
/// </summary>
public byte HeadUnloadDelay;
/// <summary>
/// Description of shugart's bus pin 34 usage
/// </summary>
public byte Pin34;
/// <summary>
/// Description of shugart's bus pin 2 usage
/// </summary>
public byte Pin2;
/// <summary>
/// Description of shugart's bus pin 4 usage
/// </summary>
public byte Pin4;
/// <summary>
/// Description of shugart's bus pin 1 usage
/// </summary>
public byte Pin1;
/// <summary>
/// Medium speed in rpm
/// </summary>
public ushort MediumRotationRate;
}
public static ModePage_05? DecodeModePage_05(byte[] pageResponse)
{
2016-04-19 02:11:47 +01:00
if(pageResponse == null)
2015-10-29 05:15:27 +00:00
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x40) == 0x40)
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x3F) != 0x05)
2015-10-29 05:15:27 +00:00
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse[1] + 2 != pageResponse.Length)
2015-10-29 05:15:27 +00:00
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse.Length < 32)
2015-10-29 05:15:27 +00:00
return null;
ModePage_05 decoded = new ModePage_05();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.TransferRate = (ushort)((pageResponse[2] << 8) + pageResponse[3]);
decoded.Heads = pageResponse[4];
decoded.SectorsPerTrack = pageResponse[5];
decoded.BytesPerSector = (ushort)((pageResponse[6] << 8) + pageResponse[7]);
decoded.Cylinders = (ushort)((pageResponse[8] << 8) + pageResponse[9]);
decoded.WritePrecompCylinder = (ushort)((pageResponse[10] << 8) + pageResponse[11]);
decoded.WriteReduceCylinder = (ushort)((pageResponse[12] << 8) + pageResponse[13]);
decoded.DriveStepRate = (ushort)((pageResponse[14] << 8) + pageResponse[15]);
decoded.DriveStepPulse = pageResponse[16];
decoded.HeadSettleDelay = (ushort)((pageResponse[17] << 8) + pageResponse[18]);
decoded.MotorOnDelay = pageResponse[19];
decoded.MotorOffDelay = pageResponse[20];
decoded.TRDY |= (pageResponse[21] & 0x80) == 0x80;
decoded.SSN |= (pageResponse[21] & 0x40) == 0x40;
decoded.MO |= (pageResponse[21] & 0x20) == 0x20;
decoded.SPC = (byte)(pageResponse[22] & 0x0F);
decoded.WriteCompensation = pageResponse[23];
decoded.HeadLoadDelay = pageResponse[24];
decoded.HeadUnloadDelay = pageResponse[25];
decoded.Pin34 = (byte)((pageResponse[26] & 0xF0) >> 4);
decoded.Pin2 = (byte)(pageResponse[26] & 0x0F);
decoded.Pin4 = (byte)((pageResponse[27] & 0xF0) >> 4);
decoded.Pin1 = (byte)(pageResponse[27] & 0x0F);
decoded.MediumRotationRate = (ushort)((pageResponse[28] << 8) + pageResponse[29]);
return decoded;
}
public static string PrettifyModePage_05(byte[] pageResponse)
{
return PrettifyModePage_05(DecodeModePage_05(pageResponse));
}
public static string PrettifyModePage_05(ModePage_05? modePage)
{
2016-04-19 02:11:47 +01:00
if(!modePage.HasValue)
2015-10-29 05:15:27 +00:00
return null;
ModePage_05 page = modePage.Value;
StringBuilder sb = new StringBuilder();
sb.AppendLine("SCSI Flexible disk page:");
2016-04-19 02:11:47 +01:00
if(page.PS)
2015-10-29 05:15:27 +00:00
sb.AppendLine("\tParameters can be saved");
sb.AppendFormat("\tTransfer rate: {0} kbit/s", page.TransferRate).AppendLine();
sb.AppendFormat("\t{0} heads", page.Heads).AppendLine();
sb.AppendFormat("\t{0} cylinders", page.Cylinders).AppendLine();
sb.AppendFormat("\t{0} sectors per track", page.SectorsPerTrack).AppendLine();
sb.AppendFormat("\t{0} bytes per sector", page.BytesPerSector).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.WritePrecompCylinder < page.Cylinders)
2015-10-29 05:15:27 +00:00
sb.AppendFormat("\tWrite pre-compensation starts at cylinder {0}", page.WritePrecompCylinder).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.WriteReduceCylinder < page.Cylinders)
2015-10-29 05:15:27 +00:00
sb.AppendFormat("\tWrite current reduction starts at cylinder {0}", page.WriteReduceCylinder).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.DriveStepRate > 0)
2015-10-29 05:15:27 +00:00
sb.AppendFormat("\tDrive steps in {0} μs", (uint)page.DriveStepRate * 100).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.DriveStepPulse > 0)
2015-10-29 05:15:27 +00:00
sb.AppendFormat("\tEach step pulse is {0} ms", page.DriveStepPulse).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.HeadSettleDelay > 0)
2015-10-29 05:15:27 +00:00
sb.AppendFormat("\tHeads settles in {0} μs", (uint)page.HeadSettleDelay * 100).AppendLine();
2016-04-19 02:11:47 +01:00
if(!page.TRDY)
2015-10-29 05:15:27 +00:00
sb.AppendFormat("\tTarget shall wait {0} seconds before attempting to access the medium after motor on is asserted",
(double)page.MotorOnDelay * 10).AppendLine();
else
sb.AppendFormat("\tTarget shall wait {0} seconds after drive is ready before aborting medium access attemps",
(double)page.MotorOnDelay * 10).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.MotorOffDelay != 0xFF)
2015-10-29 05:15:27 +00:00
sb.AppendFormat("\tTarget shall wait {0} seconds before releasing the motor on signal after becoming idle",
(double)page.MotorOffDelay * 10).AppendLine();
else
sb.AppendLine("\tTarget shall never release the motor on signal");
2016-04-19 02:11:47 +01:00
if(page.TRDY)
2015-10-29 05:15:27 +00:00
sb.AppendLine("\tThere is a drive ready signal");
2016-04-19 02:11:47 +01:00
if(page.SSN)
2015-10-29 05:15:27 +00:00
sb.AppendLine("\tSectors start at 1");
2016-04-19 02:11:47 +01:00
if(page.MO)
2015-10-29 05:15:27 +00:00
sb.AppendLine("\tThe motor on signal shall remain released");
sb.AppendFormat("\tDrive needs to do {0} step pulses per cylinder", page.SPC + 1).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.WriteCompensation > 0)
2015-10-29 05:15:27 +00:00
sb.AppendFormat("\tWrite pre-compensation is {0}", page.WriteCompensation).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.HeadLoadDelay > 0)
2015-10-29 05:15:27 +00:00
sb.AppendFormat("\tHead takes {0} ms to load", page.HeadLoadDelay).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.HeadUnloadDelay > 0)
2015-10-29 05:15:27 +00:00
sb.AppendFormat("\tHead takes {0} ms to unload", page.HeadUnloadDelay).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.MediumRotationRate > 0)
2015-10-29 05:15:27 +00:00
sb.AppendFormat("\tMedium rotates at {0} rpm", page.MediumRotationRate).AppendLine();
2016-04-19 02:11:47 +01:00
switch(page.Pin34 & 0x07)
2015-10-29 05:15:27 +00:00
{
case 0:
sb.AppendLine("\tPin 34 is unconnected");
break;
case 1:
sb.Append("\tPin 34 indicates drive is ready when active ");
2016-04-19 02:11:47 +01:00
if((page.Pin34 & 0x08) == 0x08)
2015-10-29 05:15:27 +00:00
sb.Append("high");
else
sb.Append("low");
break;
case 2:
sb.Append("\tPin 34 indicates disk has changed when active ");
2016-04-19 02:11:47 +01:00
if((page.Pin34 & 0x08) == 0x08)
2015-10-29 05:15:27 +00:00
sb.Append("high");
else
sb.Append("low");
break;
default:
sb.AppendFormat("\tPin 34 indicates unknown function {0} when active ", page.Pin34 & 0x07);
2016-04-19 02:11:47 +01:00
if((page.Pin34 & 0x08) == 0x08)
2015-10-29 05:15:27 +00:00
sb.Append("high");
else
sb.Append("low");
break;
}
2016-04-19 02:11:47 +01:00
switch(page.Pin4 & 0x07)
2015-10-29 05:15:27 +00:00
{
case 0:
sb.AppendLine("\tPin 4 is unconnected");
break;
case 1:
sb.Append("\tPin 4 indicates drive is in use when active ");
2016-04-19 02:11:47 +01:00
if((page.Pin4 & 0x08) == 0x08)
2015-10-29 05:15:27 +00:00
sb.Append("high");
else
sb.Append("low");
break;
case 2:
sb.Append("\tPin 4 indicates eject when active ");
2016-04-19 02:11:47 +01:00
if((page.Pin4 & 0x08) == 0x08)
2015-10-29 05:15:27 +00:00
sb.Append("high");
else
sb.Append("low");
break;
case 3:
sb.Append("\tPin 4 indicates head load when active ");
2016-04-19 02:11:47 +01:00
if((page.Pin4 & 0x08) == 0x08)
2015-10-29 05:15:27 +00:00
sb.Append("high");
else
sb.Append("low");
break;
default:
sb.AppendFormat("\tPin 4 indicates unknown function {0} when active ", page.Pin4 & 0x07);
2016-04-19 02:11:47 +01:00
if((page.Pin4 & 0x08) == 0x08)
2015-10-29 05:15:27 +00:00
sb.Append("high");
else
sb.Append("low");
break;
}
2016-04-19 02:11:47 +01:00
switch(page.Pin2 & 0x07)
2015-10-29 05:15:27 +00:00
{
case 0:
sb.AppendLine("\tPin 2 is unconnected");
break;
default:
sb.AppendFormat("\tPin 2 indicates unknown function {0} when active ", page.Pin2 & 0x07);
2016-04-19 02:11:47 +01:00
if((page.Pin2 & 0x08) == 0x08)
2015-10-29 05:15:27 +00:00
sb.Append("high");
else
sb.Append("low");
break;
}
2016-04-19 02:11:47 +01:00
switch(page.Pin1 & 0x07)
2015-10-29 05:15:27 +00:00
{
case 0:
sb.AppendLine("\tPin 1 is unconnected");
break;
case 1:
sb.Append("\tPin 1 indicates disk change reset when active ");
2016-04-19 02:11:47 +01:00
if((page.Pin1 & 0x08) == 0x08)
2015-10-29 05:15:27 +00:00
sb.Append("high");
else
sb.Append("low");
break;
default:
sb.AppendFormat("\tPin 1 indicates unknown function {0} when active ", page.Pin1 & 0x07);
2016-04-19 02:11:47 +01:00
if((page.Pin1 & 0x08) == 0x08)
2015-10-29 05:15:27 +00:00
sb.Append("high");
else
sb.Append("low");
break;
}
return sb.ToString();
}
2015-10-29 05:15:27 +00:00
#endregion Mode Page 0x05: Flexible disk page
2015-10-30 01:15:56 +00:00
#region Mode Page 0x03: Format device page
2015-10-30 01:15:56 +00:00
/// <summary>
/// Disconnect-reconnect page
/// Page code 0x03
/// 24 bytes in SCSI-2, SBC-1
2015-10-30 01:15:56 +00:00
/// </summary>
public struct ModePage_03
{
/// <summary>
/// Parameters can be saved
/// </summary>
public bool PS;
/// <summary>
/// Tracks per zone to use in dividing the capacity for the purpose of allocating alternate sectors
/// </summary>
public ushort TracksPerZone;
/// <summary>
/// Number of sectors per zone that shall be reserved for defect handling
/// </summary>
public ushort AltSectorsPerZone;
/// <summary>
/// Number of tracks per zone that shall be reserved for defect handling
/// </summary>
public ushort AltTracksPerZone;
/// <summary>
/// Number of tracks per LUN that shall be reserved for defect handling
/// </summary>
public ushort AltTracksPerLun;
/// <summary>
/// Number of physical sectors per track
/// </summary>
public ushort SectorsPerTrack;
/// <summary>
/// Bytes per physical sector
/// </summary>
public ushort BytesPerSector;
/// <summary>
/// Interleave value, target dependent
/// </summary>
public ushort Interleave;
/// <summary>
/// Sectors between last block of one track and first block of the next
/// </summary>
public ushort TrackSkew;
/// <summary>
/// Sectors between last block of a cylinder and first block of the next one
/// </summary>
public ushort CylinderSkew;
/// <summary>
/// Soft-sectored
/// </summary>
public bool SSEC;
/// <summary>
/// Hard-sectored
/// </summary>
public bool HSEC;
/// <summary>
/// Removable
/// </summary>
public bool RMB;
/// <summary>
/// If set, address are allocated progressively in a surface before going to the next.
/// Otherwise, it goes by cylinders
/// </summary>
public bool SURF;
}
public static ModePage_03? DecodeModePage_03(byte[] pageResponse)
{
2016-04-19 02:11:47 +01:00
if(pageResponse == null)
2015-10-30 01:15:56 +00:00
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x40) == 0x40)
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x3F) != 0x03)
2015-10-30 01:15:56 +00:00
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse[1] + 2 != pageResponse.Length)
2015-10-30 01:15:56 +00:00
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse.Length < 24)
2015-10-30 01:15:56 +00:00
return null;
ModePage_03 decoded = new ModePage_03();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.TracksPerZone = (ushort)((pageResponse[2] << 8) + pageResponse[3]);
decoded.AltSectorsPerZone = (ushort)((pageResponse[4] << 8) + pageResponse[5]);
decoded.AltTracksPerZone = (ushort)((pageResponse[6] << 8) + pageResponse[7]);
decoded.AltTracksPerLun = (ushort)((pageResponse[8] << 8) + pageResponse[9]);
decoded.SectorsPerTrack = (ushort)((pageResponse[10] << 8) + pageResponse[11]);
decoded.BytesPerSector = (ushort)((pageResponse[12] << 8) + pageResponse[13]);
decoded.Interleave = (ushort)((pageResponse[14] << 8) + pageResponse[15]);
decoded.TrackSkew = (ushort)((pageResponse[16] << 8) + pageResponse[17]);
decoded.CylinderSkew = (ushort)((pageResponse[18] << 8) + pageResponse[19]);
decoded.SSEC |= (pageResponse[20] & 0x80) == 0x80;
decoded.HSEC |= (pageResponse[20] & 0x40) == 0x40;
decoded.RMB |= (pageResponse[20] & 0x20) == 0x20;
decoded.SURF |= (pageResponse[20] & 0x10) == 0x10;
return decoded;
}
public static string PrettifyModePage_03(byte[] pageResponse)
{
return PrettifyModePage_03(DecodeModePage_03(pageResponse));
}
public static string PrettifyModePage_03(ModePage_03? modePage)
{
2016-04-19 02:11:47 +01:00
if(!modePage.HasValue)
2015-10-30 01:15:56 +00:00
return null;
ModePage_03 page = modePage.Value;
StringBuilder sb = new StringBuilder();
sb.AppendLine("SCSI Format device page:");
2016-04-19 02:11:47 +01:00
if(page.PS)
2015-10-30 01:15:56 +00:00
sb.AppendLine("\tParameters can be saved");
sb.AppendFormat("\t{0} tracks per zone to use in dividing the capacity for the purpose of allocating alternate sectors", page.TracksPerZone).AppendLine();
sb.AppendFormat("\t{0} sectors per zone that shall be reserved for defect handling", page.AltSectorsPerZone).AppendLine();
sb.AppendFormat("\t{0} tracks per zone that shall be reserved for defect handling", page.AltTracksPerZone).AppendLine();
sb.AppendFormat("\t{0} tracks per LUN that shall be reserved for defect handling", page.AltTracksPerLun).AppendLine();
sb.AppendFormat("\t{0} physical sectors per track", page.SectorsPerTrack).AppendLine();
sb.AppendFormat("\t{0} Bytes per physical sector", page.BytesPerSector).AppendLine();
sb.AppendFormat("\tTarget-dependent interleave value is {0}", page.Interleave).AppendLine();
sb.AppendFormat("\t{0} sectors between last block of one track and first block of the next", page.TrackSkew).AppendLine();
sb.AppendFormat("\t{0} sectors between last block of a cylinder and first block of the next one", page.CylinderSkew).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.SSEC)
2015-10-30 01:15:56 +00:00
sb.AppendLine("\tDrive supports soft-sectoring format");
2016-04-19 02:11:47 +01:00
if(page.HSEC)
2015-10-30 01:15:56 +00:00
sb.AppendLine("\tDrive supports hard-sectoring format");
2016-04-19 02:11:47 +01:00
if(page.RMB)
2015-10-30 01:15:56 +00:00
sb.AppendLine("\tDrive media is removable");
2016-04-19 02:11:47 +01:00
if(page.SURF)
2015-10-30 01:15:56 +00:00
sb.AppendLine("\tSector addressing is progressively incremented in one surface before going to the next");
else
sb.AppendLine("\tSector addressing is progressively incremented in one cylinder before going to the next");
return sb.ToString();
}
2015-10-30 01:15:56 +00:00
#endregion Mode Page 0x03: Format device page
2015-10-30 01:37:35 +00:00
#region Mode Page 0x0B: Medium types supported page
2015-10-30 01:37:35 +00:00
/// <summary>
/// Disconnect-reconnect page
/// Page code 0x0B
/// 8 bytes in SCSI-2
/// </summary>
public struct ModePage_0B
{
/// <summary>
/// Parameters can be saved
/// </summary>
public bool PS;
public byte MediumType1;
public byte MediumType2;
public byte MediumType3;
public byte MediumType4;
}
public static ModePage_0B? DecodeModePage_0B(byte[] pageResponse)
{
2016-04-19 02:11:47 +01:00
if(pageResponse == null)
2015-10-30 01:37:35 +00:00
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x40) == 0x40)
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x3F) != 0x0B)
2015-10-30 01:37:35 +00:00
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse[1] + 2 != pageResponse.Length)
2015-10-30 01:37:35 +00:00
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse.Length < 8)
2015-10-30 01:37:35 +00:00
return null;
ModePage_0B decoded = new ModePage_0B();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.MediumType1 = pageResponse[4];
decoded.MediumType2 = pageResponse[5];
decoded.MediumType3 = pageResponse[6];
decoded.MediumType4 = pageResponse[7];
return decoded;
}
public static string PrettifyModePage_0B(byte[] pageResponse)
{
return PrettifyModePage_0B(DecodeModePage_0B(pageResponse));
}
public static string PrettifyModePage_0B(ModePage_0B? modePage)
{
2016-04-19 02:11:47 +01:00
if(!modePage.HasValue)
2015-10-30 01:37:35 +00:00
return null;
ModePage_0B page = modePage.Value;
StringBuilder sb = new StringBuilder();
sb.AppendLine("SCSI Medium types supported page:");
2016-04-19 02:11:47 +01:00
if(page.PS)
2015-10-30 01:37:35 +00:00
sb.AppendLine("\tParameters can be saved");
// TODO: Implement it when all known medium types are supported
sb.AppendLine("Not yet implemented");
return sb.ToString();
}
2015-10-30 01:37:35 +00:00
#endregion Mode Page 0x0B: Medium types supported page
2015-10-30 02:27:07 +00:00
#region Mode Page 0x0C: Notch page
2015-10-30 02:27:07 +00:00
// TODO: Implement this page
2015-10-30 02:27:07 +00:00
#endregion Mode Page 0x0C: Notch page
#region Mode Page 0x01: Read-write error recovery page
2015-10-30 02:27:07 +00:00
/// <summary>
/// Disconnect-reconnect page
/// Page code 0x01
2015-10-31 01:31:51 +00:00
/// 12 bytes in SCSI-2, SBC-1, SBC-2
2015-10-30 02:27:07 +00:00
/// </summary>
public struct ModePage_01
{
/// <summary>
/// Parameters can be saved
/// </summary>
public bool PS;
/// <summary>
/// Automatic Write Reallocation Enabled
/// </summary>
public bool AWRE;
/// <summary>
/// Automatic Read Reallocation Enabled
/// </summary>
public bool ARRE;
/// <summary>
/// Transfer block
/// </summary>
public bool TB;
/// <summary>
/// Read continuous
/// </summary>
public bool RC;
/// <summary>
/// Enable early recovery
/// </summary>
public bool EER;
/// <summary>
/// Post error reporting
/// </summary>
public bool PER;
/// <summary>
/// Disable transfer on error
/// </summary>
public bool DTE;
/// <summary>
/// Disable correction
/// </summary>
public bool DCR;
/// <summary>
/// How many times to retry a read operation
/// </summary>
public byte ReadRetryCount;
/// <summary>
/// How many bits of largest data burst error is maximum to apply error correction on it
/// </summary>
public byte CorrectionSpan;
/// <summary>
/// Offset to move the heads
/// </summary>
public sbyte HeadOffsetCount;
/// <summary>
/// Incremental position to which the recovered data strobe shall be adjusted
/// </summary>
public sbyte DataStrobeOffsetCount;
/// <summary>
/// How many times to retry a write operation
/// </summary>
public byte WriteRetryCount;
/// <summary>
/// Maximum time in ms to use in data error recovery procedures
/// </summary>
public ushort RecoveryTimeLimit;
2015-10-31 01:38:27 +00:00
/// <summary>
/// Logical block provisioning error reporting is enabled
/// </summary>
public bool LBPERE;
2015-10-30 02:27:07 +00:00
}
public static ModePage_01? DecodeModePage_01(byte[] pageResponse)
{
2016-04-19 02:11:47 +01:00
if(pageResponse == null)
2015-10-30 02:27:07 +00:00
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x40) == 0x40)
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x3F) != 0x01)
2015-10-30 02:27:07 +00:00
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse[1] + 2 != pageResponse.Length)
2015-10-30 02:27:07 +00:00
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse.Length < 8)
2015-10-30 02:27:07 +00:00
return null;
ModePage_01 decoded = new ModePage_01();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.AWRE |= (pageResponse[2] & 0x80) == 0x80;
decoded.ARRE |= (pageResponse[2] & 0x40) == 0x40;
decoded.TB |= (pageResponse[2] & 0x20) == 0x20;
decoded.RC |= (pageResponse[2] & 0x10) == 0x10;
decoded.EER |= (pageResponse[2] & 0x08) == 0x08;
decoded.PER |= (pageResponse[2] & 0x04) == 0x04;
decoded.DTE |= (pageResponse[2] & 0x02) == 0x02;
decoded.DCR |= (pageResponse[2] & 0x01) == 0x01;
decoded.ReadRetryCount = pageResponse[3];
decoded.CorrectionSpan = pageResponse[4];
decoded.HeadOffsetCount = (sbyte)pageResponse[5];
decoded.DataStrobeOffsetCount = (sbyte)pageResponse[6];
2016-04-19 02:11:47 +01:00
if(pageResponse.Length < 12)
return decoded;
2015-10-30 02:27:07 +00:00
decoded.WriteRetryCount = pageResponse[8];
decoded.RecoveryTimeLimit = (ushort)((pageResponse[10] << 8) + pageResponse[11]);
2015-10-31 01:38:27 +00:00
decoded.LBPERE |= (pageResponse[7] & 0x80) == 0x80;
2015-10-30 02:27:07 +00:00
return decoded;
}
public static string PrettifyModePage_01(byte[] pageResponse)
{
return PrettifyModePage_01(DecodeModePage_01(pageResponse));
}
public static string PrettifyModePage_01(ModePage_01? modePage)
{
2016-04-19 02:11:47 +01:00
if(!modePage.HasValue)
2015-10-30 02:27:07 +00:00
return null;
ModePage_01 page = modePage.Value;
StringBuilder sb = new StringBuilder();
sb.AppendLine("SCSI Read-write error recovery page:");
2016-04-19 02:11:47 +01:00
if(page.PS)
2015-10-30 02:27:07 +00:00
sb.AppendLine("\tParameters can be saved");
2016-04-19 02:11:47 +01:00
if(page.AWRE)
2015-10-30 02:27:07 +00:00
sb.AppendLine("\tAutomatic write reallocation is enabled");
2016-04-19 02:11:47 +01:00
if(page.ARRE)
2015-10-30 02:27:07 +00:00
sb.AppendLine("\tAutomatic read reallocation is enabled");
2016-04-19 02:11:47 +01:00
if(page.TB)
2015-10-30 02:27:07 +00:00
sb.AppendLine("\tData not recovered within limits shall be transferred back before a CHECK CONDITION");
2016-04-19 02:11:47 +01:00
if(page.RC)
2015-10-30 02:27:07 +00:00
sb.AppendLine("\tDrive will transfer the entire requested length without delaying to perform error recovery");
2016-04-19 02:11:47 +01:00
if(page.EER)
2015-10-30 02:27:07 +00:00
sb.AppendLine("\tDrive will use the most expedient form of error recovery first");
2016-04-19 02:11:47 +01:00
if(page.PER)
2015-10-30 02:27:07 +00:00
sb.AppendLine("\tDrive shall report recovered errors");
2016-04-19 02:11:47 +01:00
if(page.DTE)
2015-10-30 02:27:07 +00:00
sb.AppendLine("\tTransfer will be terminated upon error detection");
2016-04-19 02:11:47 +01:00
if(page.DCR)
2015-10-30 02:27:07 +00:00
sb.AppendLine("\tError correction is disabled");
2016-04-19 02:11:47 +01:00
if(page.ReadRetryCount > 0)
2015-10-30 02:27:07 +00:00
sb.AppendFormat("\tDrive will repeat read operations {0} times", page.ReadRetryCount).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.WriteRetryCount > 0)
2015-10-30 02:27:07 +00:00
sb.AppendFormat("\tDrive will repeat write operations {0} times", page.WriteRetryCount).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.RecoveryTimeLimit > 0)
2015-10-30 02:27:07 +00:00
sb.AppendFormat("\tDrive will employ a maximum of {0} ms to recover data", page.RecoveryTimeLimit).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.LBPERE)
2015-10-31 01:38:27 +00:00
sb.AppendLine("Logical block provisioning error reporting is enabled");
2015-10-30 02:27:07 +00:00
return sb.ToString();
}
2015-10-30 02:27:07 +00:00
#endregion Mode Page 0x01: Read-write error recovery page
2015-10-30 02:50:05 +00:00
#region Mode Page 0x04: Rigid disk drive geometry page
2015-10-30 02:50:05 +00:00
/// <summary>
/// Disconnect-reconnect page
/// Page code 0x04
/// 24 bytes in SCSI-2, SBC-1
2015-10-30 02:50:05 +00:00
/// </summary>
public struct ModePage_04
{
/// <summary>
/// Parameters can be saved
/// </summary>
public bool PS;
/// <summary>
/// Cylinders used for data storage
/// </summary>
public uint Cylinders;
/// <summary>
/// Heads for reading and/or writing
/// </summary>
public byte Heads;
/// <summary>
/// Cylinder where write precompensation starts
/// </summary>
public uint WritePrecompCylinder;
/// <summary>
/// Cylinder where write current reduction starts
/// </summary>
public uint WriteReduceCylinder;
/// <summary>
/// Step rate in 100 ns units
/// </summary>
public ushort DriveStepRate;
/// <summary>
/// Cylinder where the heads park
/// </summary>
public int LandingCylinder;
/// <summary>
/// Rotational position locking
/// </summary>
public byte RPL;
/// <summary>
/// Rotational skew to apply when synchronized
/// </summary>
public byte RotationalOffset;
/// <summary>
/// Medium speed in rpm
/// </summary>
public ushort MediumRotationRate;
}
public static ModePage_04? DecodeModePage_04(byte[] pageResponse)
{
2016-04-19 02:11:47 +01:00
if(pageResponse == null)
2015-10-30 02:50:05 +00:00
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x40) == 0x40)
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x3F) != 0x04)
2015-10-30 02:50:05 +00:00
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse[1] + 2 != pageResponse.Length)
2015-10-30 02:50:05 +00:00
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse.Length < 24)
2015-10-30 02:50:05 +00:00
return null;
ModePage_04 decoded = new ModePage_04();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.Cylinders = (uint)((pageResponse[2] << 16) + (pageResponse[3] << 8) + pageResponse[4]);
decoded.Heads = pageResponse[5];
decoded.WritePrecompCylinder = (uint)((pageResponse[6] << 16) + (pageResponse[7] << 8) + pageResponse[8]);
decoded.WriteReduceCylinder = (uint)((pageResponse[9] << 16) + (pageResponse[10] << 8) + pageResponse[11]);
decoded.DriveStepRate = (ushort)((pageResponse[12] << 8) + pageResponse[13]);
decoded.LandingCylinder = ((pageResponse[14] << 16) + (pageResponse[15] << 8) + pageResponse[16]);
decoded.RPL = (byte)(pageResponse[17] & 0x03);
decoded.RotationalOffset = pageResponse[18];
decoded.MediumRotationRate = (ushort)((pageResponse[20] << 8) + pageResponse[21]);
return decoded;
}
public static string PrettifyModePage_04(byte[] pageResponse)
{
return PrettifyModePage_04(DecodeModePage_04(pageResponse));
}
public static string PrettifyModePage_04(ModePage_04? modePage)
{
2016-04-19 02:11:47 +01:00
if(!modePage.HasValue)
2015-10-30 02:50:05 +00:00
return null;
ModePage_04 page = modePage.Value;
StringBuilder sb = new StringBuilder();
sb.AppendLine("SCSI Rigid disk drive geometry page:");
2016-04-19 02:11:47 +01:00
if(page.PS)
2015-10-30 02:50:05 +00:00
sb.AppendLine("\tParameters can be saved");
sb.AppendFormat("\t{0} heads", page.Heads).AppendLine();
sb.AppendFormat("\t{0} cylinders", page.Cylinders).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.WritePrecompCylinder < page.Cylinders)
2015-10-30 02:50:05 +00:00
sb.AppendFormat("\tWrite pre-compensation starts at cylinder {0}", page.WritePrecompCylinder).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.WriteReduceCylinder < page.Cylinders)
2015-10-30 02:50:05 +00:00
sb.AppendFormat("\tWrite current reduction starts at cylinder {0}", page.WriteReduceCylinder).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.DriveStepRate > 0)
2015-10-30 02:50:05 +00:00
sb.AppendFormat("\tDrive steps in {0} ns", (uint)page.DriveStepRate * 100).AppendLine();
sb.AppendFormat("\tHeads park in cylinder {0}", page.LandingCylinder).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.MediumRotationRate > 0)
2015-10-30 02:50:05 +00:00
sb.AppendFormat("\tMedium rotates at {0} rpm", page.MediumRotationRate).AppendLine();
2016-04-19 02:11:47 +01:00
switch(page.RPL)
2015-10-30 02:50:05 +00:00
{
case 0:
sb.AppendLine("\tSpindle synchronization is disable or unsupported");
break;
case 1:
sb.AppendLine("\tTarget operates as a synchronized-spindle slave");
break;
case 2:
sb.AppendLine("\tTarget operates as a synchronized-spindle master");
break;
case 3:
sb.AppendLine("\tTarget operates as a synchronized-spindle master control");
break;
}
return sb.ToString();
}
2015-10-30 02:50:05 +00:00
#endregion Mode Page 0x04: Rigid disk drive geometry page
2015-10-30 02:53:36 +00:00
#region Mode Page 0x07: Verify error recovery page
2015-10-30 02:53:36 +00:00
/// <summary>
/// Disconnect-reconnect page
/// Page code 0x07
2015-10-31 01:31:51 +00:00
/// 12 bytes in SCSI-2, SBC-1, SBC-2
2015-10-30 02:53:36 +00:00
/// </summary>
public struct ModePage_07
{
/// <summary>
/// Parameters can be saved
/// </summary>
public bool PS;
/// <summary>
/// Enable early recovery
/// </summary>
public bool EER;
/// <summary>
/// Post error reporting
/// </summary>
public bool PER;
/// <summary>
/// Disable transfer on error
/// </summary>
public bool DTE;
/// <summary>
/// Disable correction
/// </summary>
public bool DCR;
/// <summary>
/// How many times to retry a verify operation
/// </summary>
public byte VerifyRetryCount;
/// <summary>
/// How many bits of largest data burst error is maximum to apply error correction on it
/// </summary>
public byte CorrectionSpan;
/// <summary>
/// Maximum time in ms to use in data error recovery procedures
/// </summary>
public ushort RecoveryTimeLimit;
}
public static ModePage_07? DecodeModePage_07(byte[] pageResponse)
{
2016-04-19 02:11:47 +01:00
if(pageResponse == null)
2015-10-30 02:53:36 +00:00
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x40) == 0x40)
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x3F) != 0x07)
2015-10-30 02:53:36 +00:00
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse[1] + 2 != pageResponse.Length)
2015-10-30 02:53:36 +00:00
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse.Length < 12)
2015-10-30 02:53:36 +00:00
return null;
ModePage_07 decoded = new ModePage_07();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.EER |= (pageResponse[2] & 0x08) == 0x08;
decoded.PER |= (pageResponse[2] & 0x04) == 0x04;
decoded.DTE |= (pageResponse[2] & 0x02) == 0x02;
decoded.DCR |= (pageResponse[2] & 0x01) == 0x01;
decoded.VerifyRetryCount = pageResponse[3];
decoded.CorrectionSpan = pageResponse[4];
decoded.RecoveryTimeLimit = (ushort)((pageResponse[10] << 8) + pageResponse[11]);
return decoded;
}
public static string PrettifyModePage_07(byte[] pageResponse)
{
return PrettifyModePage_07(DecodeModePage_07(pageResponse));
}
public static string PrettifyModePage_07(ModePage_07? modePage)
{
2016-04-19 02:11:47 +01:00
if(!modePage.HasValue)
2015-10-30 02:53:36 +00:00
return null;
ModePage_07 page = modePage.Value;
StringBuilder sb = new StringBuilder();
sb.AppendLine("SCSI Verify error recovery page:");
2016-04-19 02:11:47 +01:00
if(page.PS)
2015-10-30 02:53:36 +00:00
sb.AppendLine("\tParameters can be saved");
2016-04-19 02:11:47 +01:00
if(page.EER)
2015-10-30 02:53:36 +00:00
sb.AppendLine("\tDrive will use the most expedient form of error recovery first");
2016-04-19 02:11:47 +01:00
if(page.PER)
2015-10-30 02:53:36 +00:00
sb.AppendLine("\tDrive shall report recovered errors");
2016-04-19 02:11:47 +01:00
if(page.DTE)
2015-10-30 02:53:36 +00:00
sb.AppendLine("\tTransfer will be terminated upon error detection");
2016-04-19 02:11:47 +01:00
if(page.DCR)
2015-10-30 02:53:36 +00:00
sb.AppendLine("\tError correction is disabled");
2016-04-19 02:11:47 +01:00
if(page.VerifyRetryCount > 0)
2015-10-30 02:53:36 +00:00
sb.AppendFormat("\tDrive will repeat verify operations {0} times", page.VerifyRetryCount).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.RecoveryTimeLimit > 0)
2015-10-30 02:53:36 +00:00
sb.AppendFormat("\tDrive will employ a maximum of {0} ms to recover data", page.RecoveryTimeLimit).AppendLine();
return sb.ToString();
}
2015-10-30 02:53:36 +00:00
#endregion Mode Page 0x07: Verify error recovery page
2015-10-30 03:29:58 +00:00
#region Mode Page 0x10: Device configuration page
2015-10-30 03:29:58 +00:00
/// <summary>
/// Device configuration page
/// Page code 0x10
/// 16 bytes in SCSI-2, SSC-1, SSC-2, SSC-3
2015-10-30 03:29:58 +00:00
/// </summary>
public struct ModePage_10_SSC
2015-10-30 03:29:58 +00:00
{
/// <summary>
/// Parameters can be saved
/// </summary>
public bool PS;
/// <summary>
/// Used in mode select to change partition to one specified in <see cref="ActivePartition"/>
/// </summary>
public bool CAP;
/// <summary>
/// Used in mode select to change format to one specified in <see cref="ActiveFormat"/>
/// </summary>
public bool CAF;
/// <summary>
/// Active format, vendor-specific
/// </summary>
public byte ActiveFormat;
/// <summary>
/// Current logical partition
/// </summary>
public byte ActivePartition;
/// <summary>
/// How full the buffer shall be before writing to medium
/// </summary>
public byte WriteBufferFullRatio;
/// <summary>
/// How empty the buffer shall be before reading more data from the medium
/// </summary>
public byte ReadBufferEmptyRatio;
/// <summary>
/// Delay in 100 ms before buffered data is forcefully written to the medium even before buffer is full
/// </summary>
public ushort WriteDelayTime;
/// <summary>
/// Drive supports recovering data from buffer
/// </summary>
public bool DBR;
/// <summary>
/// Medium has block IDs
/// </summary>
public bool BIS;
/// <summary>
/// Drive recognizes and reports setmarks
/// </summary>
public bool RSmk;
/// <summary>
/// Drive selects best speed
/// </summary>
public bool AVC;
/// <summary>
/// If drive should stop pre-reading on filemarks
/// </summary>
public byte SOCF;
/// <summary>
/// If set, recovered buffer data is LIFO, otherwise, FIFO
/// </summary>
public bool RBO;
/// <summary>
/// Report early warnings
/// </summary>
public bool REW;
/// <summary>
/// Inter-block gap
/// </summary>
public byte GapSize;
/// <summary>
/// End-of-Data format
/// </summary>
public byte EODDefined;
/// <summary>
/// EOD generation enabled
/// </summary>
public bool EEG;
/// <summary>
/// Synchronize data to medium on early warning
/// </summary>
public bool SEW;
/// <summary>
/// Bytes to reduce buffer size on early warning
/// </summary>
public uint BufferSizeEarlyWarning;
/// <summary>
/// Selected data compression algorithm
/// </summary>
public byte SelectedCompression;
2015-10-31 02:34:45 +00:00
/// <summary>
/// Soft write protect
/// </summary>
public bool SWP;
/// <summary>
/// Associated write protect
/// </summary>
public bool ASOCWP;
/// <summary>
/// Persistent write protect
/// </summary>
public bool PERSWP;
/// <summary>
/// Permanent write protect
/// </summary>
public bool PRMWP;
2015-10-31 02:48:34 +00:00
public bool BAML;
public bool BAM;
public byte RewindOnReset;
/// <summary>
/// How drive shall respond to detection of compromised WORM medium integrity
/// </summary>
public byte WTRE;
/// <summary>
/// Respond to commands only if a reservation exists
/// </summary>
public bool OIR;
2015-10-30 03:29:58 +00:00
}
public static ModePage_10_SSC? DecodeModePage_10_SSC(byte[] pageResponse)
2015-10-30 03:29:58 +00:00
{
2016-04-19 02:11:47 +01:00
if(pageResponse == null)
2015-10-30 03:29:58 +00:00
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x40) == 0x40)
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x3F) != 0x10)
2015-10-30 03:29:58 +00:00
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse[1] + 2 != pageResponse.Length)
2015-10-30 03:29:58 +00:00
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse.Length < 16)
2015-10-30 03:29:58 +00:00
return null;
ModePage_10_SSC decoded = new ModePage_10_SSC();
2015-10-30 03:29:58 +00:00
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.CAP |= (pageResponse[2] & 0x40) == 0x40;
decoded.CAF |= (pageResponse[2] & 0x20) == 0x20;
decoded.ActiveFormat = (byte)(pageResponse[2] & 0x1F);
decoded.ActivePartition = pageResponse[3];
decoded.WriteBufferFullRatio = pageResponse[4];
decoded.ReadBufferEmptyRatio = pageResponse[5];
decoded.WriteDelayTime = (ushort)((pageResponse[6] << 8) + pageResponse[7]);
decoded.DBR |= (pageResponse[8] & 0x80) == 0x80;
decoded.BIS |= (pageResponse[8] & 0x40) == 0x40;
decoded.RSmk |= (pageResponse[8] & 0x20) == 0x20;
decoded.AVC |= (pageResponse[8] & 0x10) == 0x10;
decoded.RBO |= (pageResponse[8] & 0x02) == 0x02;
decoded.REW |= (pageResponse[8] & 0x01) == 0x01;
decoded.EEG |= (pageResponse[10] & 0x10) == 0x10;
decoded.SEW |= (pageResponse[10] & 0x08) == 0x08;
decoded.SOCF = (byte)((pageResponse[8] & 0x0C) >> 2);
decoded.BufferSizeEarlyWarning = (uint)((pageResponse[11] << 16) + (pageResponse[12] << 8) + pageResponse[13]);
decoded.SelectedCompression = pageResponse[14];
2015-10-31 02:34:45 +00:00
decoded.SWP |= (pageResponse[10] & 0x04) == 0x04;
decoded.ASOCWP |= (pageResponse[15] & 0x04) == 0x04;
decoded.PERSWP |= (pageResponse[15] & 0x02) == 0x02;
decoded.PRMWP |= (pageResponse[15] & 0x01) == 0x01;
2015-10-31 02:48:34 +00:00
decoded.BAML |= (pageResponse[10] & 0x02) == 0x02;
decoded.BAM |= (pageResponse[10] & 0x01) == 0x01;
decoded.RewindOnReset = (byte)((pageResponse[15] & 0x18) >> 3);
decoded.OIR |= (pageResponse[15] & 0x20) == 0x20;
decoded.WTRE = (byte)((pageResponse[15] & 0xC0) >> 6);
2015-10-30 03:29:58 +00:00
return decoded;
}
public static string PrettifyModePage_10_SSC(byte[] pageResponse)
2015-10-30 03:29:58 +00:00
{
return PrettifyModePage_10_SSC(DecodeModePage_10_SSC(pageResponse));
2015-10-30 03:29:58 +00:00
}
public static string PrettifyModePage_10_SSC(ModePage_10_SSC? modePage)
2015-10-30 03:29:58 +00:00
{
2016-04-19 02:11:47 +01:00
if(!modePage.HasValue)
2015-10-30 03:29:58 +00:00
return null;
ModePage_10_SSC page = modePage.Value;
2015-10-30 03:29:58 +00:00
StringBuilder sb = new StringBuilder();
sb.AppendLine("SCSI Device configuration page:");
2016-04-19 02:11:47 +01:00
if(page.PS)
2015-10-30 03:29:58 +00:00
sb.AppendLine("\tParameters can be saved");
2016-04-19 02:11:47 +01:00
2015-10-30 03:29:58 +00:00
sb.AppendFormat("\tActive format: {0}", page.ActiveFormat).AppendLine();
sb.AppendFormat("\tActive partition: {0}", page.ActivePartition).AppendLine();
sb.AppendFormat("\tWrite buffer shall have a full ratio of {0} before being flushed to medium", page.WriteBufferFullRatio).AppendLine();
sb.AppendFormat("\tRead buffer shall have an empty ratio of {0} before more data is read from medium", page.ReadBufferEmptyRatio).AppendLine();
sb.AppendFormat("\tDrive will delay {0} ms before buffered data is forcefully written to the medium even before buffer is full", (int)page.WriteDelayTime * 100).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.DBR)
2015-10-30 03:29:58 +00:00
{
sb.AppendLine("\tDrive supports recovering data from buffer");
2016-04-19 02:11:47 +01:00
if(page.RBO)
2015-10-30 03:29:58 +00:00
sb.AppendLine("\tRecovered buffer data comes in LIFO order");
else
sb.AppendLine("\tRecovered buffer data comes in FIFO order");
}
2016-04-19 02:11:47 +01:00
if(page.BIS)
2015-10-30 03:29:58 +00:00
sb.AppendLine("\tMedium supports block IDs");
2016-04-19 02:11:47 +01:00
if(page.RSmk)
2015-10-30 03:29:58 +00:00
sb.AppendLine("\tDrive reports setmarks");
2016-04-19 02:11:47 +01:00
switch(page.SOCF)
2015-10-30 03:29:58 +00:00
{
case 0:
sb.AppendLine("\tDrive will pre-read until buffer is full");
break;
case 1:
sb.AppendLine("\tDrive will pre-read until one filemark is detected");
break;
case 2:
sb.AppendLine("\tDrive will pre-read until two filemark is detected");
break;
case 3:
sb.AppendLine("\tDrive will pre-read until three filemark is detected");
break;
}
2016-04-19 02:11:47 +01:00
if(page.REW)
2015-10-30 03:29:58 +00:00
{
sb.AppendLine("\tDrive reports early warnings");
2016-04-19 02:11:47 +01:00
if(page.SEW)
2015-10-30 03:29:58 +00:00
sb.AppendLine("\tDrive will synchronize buffer to medium on early warnings");
}
2016-04-19 02:11:47 +01:00
switch(page.GapSize)
2015-10-30 03:29:58 +00:00
{
case 0:
break;
case 1:
sb.AppendLine("\tInter-block gap is long enough to support update in place");
break;
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
case 10:
case 11:
case 12:
case 13:
case 14:
case 15:
sb.AppendFormat("\tInter-block gap is {0} times the device's defined gap size", page.GapSize).AppendLine();
break;
default:
sb.AppendFormat("\tInter-block gap is unknown value {0}", page.GapSize).AppendLine();
break;
}
2016-04-19 02:11:47 +01:00
if(page.EEG)
2015-10-30 03:29:58 +00:00
sb.AppendLine("\tDrive generates end-of-data");
2016-04-19 02:11:47 +01:00
switch(page.SelectedCompression)
2015-10-30 03:29:58 +00:00
{
case 0:
sb.AppendLine("\tDrive does not use compression");
break;
case 1:
sb.AppendLine("\tDrive uses default compression");
break;
default:
sb.AppendFormat("\tDrive uses unknown compression {0}", page.SelectedCompression).AppendLine();
break;
}
2016-04-19 02:11:47 +01:00
if(page.SWP)
2015-10-31 02:34:45 +00:00
sb.AppendLine("\tSoftware write protect is enabled");
2016-04-19 02:11:47 +01:00
if(page.ASOCWP)
2015-10-31 02:34:45 +00:00
sb.AppendLine("\tAssociated write protect is enabled");
2016-04-19 02:11:47 +01:00
if(page.PERSWP)
2015-10-31 02:34:45 +00:00
sb.AppendLine("\tPersistent write protect is enabled");
2016-04-19 02:11:47 +01:00
if(page.PRMWP)
2015-10-31 02:34:45 +00:00
sb.AppendLine("\tPermanent write protect is enabled");
2016-04-19 02:11:47 +01:00
if(page.BAML)
2015-10-31 02:48:34 +00:00
{
2016-04-19 02:11:47 +01:00
if(page.BAM)
2015-10-31 02:48:34 +00:00
sb.AppendLine("\tDrive operates using explicit address mode");
else
sb.AppendLine("\tDrive operates using implicit address mode");
}
2016-04-19 02:11:47 +01:00
switch(page.RewindOnReset)
2015-10-31 02:48:34 +00:00
{
case 1:
sb.AppendLine("\tDrive shall position to beginning of default data partition on reset");
break;
case 2:
sb.AppendLine("\tDrive shall maintain its position on reset");
break;
}
2016-04-19 02:11:47 +01:00
switch(page.WTRE)
{
case 1:
sb.AppendLine("\tDrive will do nothing on WORM tampered medium");
break;
case 2:
sb.AppendLine("\tDrive will return CHECK CONDITION on WORM tampered medium");
break;
}
2016-04-19 02:11:47 +01:00
if(page.OIR)
sb.AppendLine("\tDrive will only respond to commands if it has received a reservation");
2015-10-30 03:29:58 +00:00
return sb.ToString();
}
2015-10-30 03:29:58 +00:00
#endregion Mode Page 0x10: Device configuration page
2015-10-30 03:52:24 +00:00
#region Mode Page 0x0E: CD-ROM audio control parameters page
2015-10-30 03:52:24 +00:00
/// <summary>
/// CD-ROM audio control parameters
/// Page code 0x0E
2015-10-31 06:29:39 +00:00
/// 16 bytes in SCSI-2, MMC-1, MMC-2, MMC-3
2015-10-30 03:52:24 +00:00
/// </summary>
public struct ModePage_0E
{
/// <summary>
/// Parameters can be saved
/// </summary>
public bool PS;
/// <summary>
/// Return status as soon as playback operation starts
/// </summary>
public bool Immed;
/// <summary>
/// Stop on track crossing
/// </summary>
public bool SOTC;
/// <summary>
/// Indicates <see cref="BlocksPerSecondOfAudio"/> is valid
/// </summary>
public bool APRVal;
/// <summary>
/// Multiplier for <see cref="BlocksPerSecondOfAudio"/>
/// </summary>
public byte LBAFormat;
/// <summary>
/// LBAs per second of audio
/// </summary>
public ushort BlocksPerSecondOfAudio;
/// <summary>
/// Channels output on this port
/// </summary>
public byte OutputPort0ChannelSelection;
/// <summary>
/// Volume level for this port
/// </summary>
public byte OutputPort0Volume;
/// <summary>
/// Channels output on this port
/// </summary>
public byte OutputPort1ChannelSelection;
/// <summary>
/// Volume level for this port
/// </summary>
public byte OutputPort1Volume;
/// <summary>
/// Channels output on this port
/// </summary>
public byte OutputPort2ChannelSelection;
/// <summary>
/// Volume level for this port
/// </summary>
public byte OutputPort2Volume;
/// <summary>
/// Channels output on this port
/// </summary>
public byte OutputPort3ChannelSelection;
/// <summary>
/// Volume level for this port
/// </summary>
public byte OutputPort3Volume;
}
public static ModePage_0E? DecodeModePage_0E(byte[] pageResponse)
{
2016-04-19 02:11:47 +01:00
if(pageResponse == null)
2015-10-30 03:52:24 +00:00
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x40) == 0x40)
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x3F) != 0x0E)
2015-10-30 03:52:24 +00:00
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse[1] + 2 != pageResponse.Length)
2015-10-30 03:52:24 +00:00
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse.Length < 16)
2015-10-30 03:52:24 +00:00
return null;
ModePage_0E decoded = new ModePage_0E();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.Immed |= (pageResponse[2] & 0x04) == 0x04;
decoded.SOTC |= (pageResponse[2] & 0x02) == 0x02;
decoded.APRVal |= (pageResponse[5] & 0x80) == 0x80;
decoded.LBAFormat = (byte)(pageResponse[5] & 0x0F);
decoded.BlocksPerSecondOfAudio = (ushort)((pageResponse[6] << 8) + pageResponse[7]);
decoded.OutputPort0ChannelSelection = (byte)(pageResponse[8] & 0x0F);
decoded.OutputPort0Volume = pageResponse[9];
decoded.OutputPort1ChannelSelection = (byte)(pageResponse[10] & 0x0F);
decoded.OutputPort1Volume = pageResponse[11];
decoded.OutputPort2ChannelSelection = (byte)(pageResponse[12] & 0x0F);
decoded.OutputPort2Volume = pageResponse[13];
decoded.OutputPort3ChannelSelection = (byte)(pageResponse[14] & 0x0F);
decoded.OutputPort3Volume = pageResponse[15];
return decoded;
}
public static string PrettifyModePage_0E(byte[] pageResponse)
{
return PrettifyModePage_0E(DecodeModePage_0E(pageResponse));
}
public static string PrettifyModePage_0E(ModePage_0E? modePage)
{
2016-04-19 02:11:47 +01:00
if(!modePage.HasValue)
2015-10-30 03:52:24 +00:00
return null;
ModePage_0E page = modePage.Value;
StringBuilder sb = new StringBuilder();
sb.AppendLine("SCSI CD-ROM audio control parameters page:");
2016-04-19 02:11:47 +01:00
if(page.PS)
2015-10-30 03:52:24 +00:00
sb.AppendLine("\tParameters can be saved");
2016-04-19 02:11:47 +01:00
if(page.Immed)
2015-10-30 03:52:24 +00:00
sb.AppendLine("\tDrive will return from playback command immediately");
else
sb.AppendLine("\tDrive will return from playback command when playback ends");
2016-04-19 02:11:47 +01:00
if(page.SOTC)
2015-10-30 03:52:24 +00:00
sb.AppendLine("\tDrive will stop playback on track end");
2016-04-19 02:11:47 +01:00
if(page.APRVal)
2015-10-30 03:52:24 +00:00
{
double blocks;
2016-04-19 02:11:47 +01:00
if(page.LBAFormat == 8)
2015-10-30 03:52:24 +00:00
blocks = page.BlocksPerSecondOfAudio * (1 / 256);
else
blocks = page.BlocksPerSecondOfAudio;
sb.AppendFormat("\tThere are {0} blocks per each second of audio", blocks).AppendLine();
}
2016-04-19 02:11:47 +01:00
if(page.OutputPort0ChannelSelection > 0)
2015-10-30 03:52:24 +00:00
{
sb.Append("\tOutput port 0 has channels ");
2016-04-19 02:11:47 +01:00
if((page.OutputPort0ChannelSelection & 0x01) == 0x01)
2015-10-30 03:52:24 +00:00
sb.Append("0 ");
2016-04-19 02:11:47 +01:00
if((page.OutputPort0ChannelSelection & 0x02) == 0x02)
2015-10-30 03:52:24 +00:00
sb.Append("1 ");
2016-04-19 02:11:47 +01:00
if((page.OutputPort0ChannelSelection & 0x04) == 0x04)
2015-10-30 03:52:24 +00:00
sb.Append("2 ");
2016-04-19 02:11:47 +01:00
if((page.OutputPort0ChannelSelection & 0x08) == 0x08)
2015-10-30 03:52:24 +00:00
sb.Append("3 ");
2016-04-19 02:11:47 +01:00
switch(page.OutputPort0Volume)
2015-10-30 03:52:24 +00:00
{
case 0:
sb.AppendLine("muted");
break;
case 0xFF:
sb.AppendLine("at maximum volume");
break;
default:
sb.AppendFormat("at volume {0}", page.OutputPort0Volume).AppendLine();
break;
}
}
2016-04-19 02:11:47 +01:00
if(page.OutputPort1ChannelSelection > 0)
2015-10-30 03:52:24 +00:00
{
sb.Append("\tOutput port 1 has channels ");
2016-04-19 02:11:47 +01:00
if((page.OutputPort1ChannelSelection & 0x01) == 0x01)
2015-10-30 03:52:24 +00:00
sb.Append("0 ");
2016-04-19 02:11:47 +01:00
if((page.OutputPort1ChannelSelection & 0x02) == 0x02)
2015-10-30 03:52:24 +00:00
sb.Append("1 ");
2016-04-19 02:11:47 +01:00
if((page.OutputPort1ChannelSelection & 0x04) == 0x04)
2015-10-30 03:52:24 +00:00
sb.Append("2 ");
2016-04-19 02:11:47 +01:00
if((page.OutputPort1ChannelSelection & 0x08) == 0x08)
2015-10-30 03:52:24 +00:00
sb.Append("3 ");
2016-04-19 02:11:47 +01:00
switch(page.OutputPort1Volume)
2015-10-30 03:52:24 +00:00
{
case 0:
sb.AppendLine("muted");
break;
case 0xFF:
sb.AppendLine("at maximum volume");
break;
default:
sb.AppendFormat("at volume {0}", page.OutputPort1Volume).AppendLine();
break;
}
}
2016-04-19 02:11:47 +01:00
if(page.OutputPort2ChannelSelection > 0)
2015-10-30 03:52:24 +00:00
{
sb.Append("\tOutput port 2 has channels ");
2016-04-19 02:11:47 +01:00
if((page.OutputPort2ChannelSelection & 0x01) == 0x01)
2015-10-30 03:52:24 +00:00
sb.Append("0 ");
2016-04-19 02:11:47 +01:00
if((page.OutputPort2ChannelSelection & 0x02) == 0x02)
2015-10-30 03:52:24 +00:00
sb.Append("1 ");
2016-04-19 02:11:47 +01:00
if((page.OutputPort2ChannelSelection & 0x04) == 0x04)
2015-10-30 03:52:24 +00:00
sb.Append("2 ");
2016-04-19 02:11:47 +01:00
if((page.OutputPort2ChannelSelection & 0x08) == 0x08)
2015-10-30 03:52:24 +00:00
sb.Append("3 ");
2016-04-19 02:11:47 +01:00
switch(page.OutputPort2Volume)
2015-10-30 03:52:24 +00:00
{
case 0:
sb.AppendLine("muted");
break;
case 0xFF:
sb.AppendLine("at maximum volume");
break;
default:
sb.AppendFormat("at volume {0}", page.OutputPort2Volume).AppendLine();
break;
}
}
2016-04-19 02:11:47 +01:00
if(page.OutputPort3ChannelSelection > 0)
2015-10-30 03:52:24 +00:00
{
sb.Append("\tOutput port 3 has channels ");
2016-04-19 02:11:47 +01:00
if((page.OutputPort3ChannelSelection & 0x01) == 0x01)
2015-10-30 03:52:24 +00:00
sb.Append("0 ");
2016-04-19 02:11:47 +01:00
if((page.OutputPort3ChannelSelection & 0x02) == 0x02)
2015-10-30 03:52:24 +00:00
sb.Append("1 ");
2016-04-19 02:11:47 +01:00
if((page.OutputPort3ChannelSelection & 0x04) == 0x04)
2015-10-30 03:52:24 +00:00
sb.Append("2 ");
2016-04-19 02:11:47 +01:00
if((page.OutputPort3ChannelSelection & 0x08) == 0x08)
2015-10-30 03:52:24 +00:00
sb.Append("3 ");
2016-04-19 02:11:47 +01:00
switch(page.OutputPort3Volume)
2015-10-30 03:52:24 +00:00
{
case 0:
sb.AppendLine("muted");
break;
case 0xFF:
sb.AppendLine("at maximum volume");
break;
default:
sb.AppendFormat("at volume {0}", page.OutputPort3Volume).AppendLine();
break;
}
}
return sb.ToString();
}
2015-10-30 03:52:24 +00:00
#endregion Mode Page 0x0E: CD-ROM audio control parameters page
2015-10-30 17:11:16 +00:00
#region Mode Page 0x0D: CD-ROM parameteres page
2015-10-30 17:11:16 +00:00
/// <summary>
/// CD-ROM parameteres page
/// Page code 0x0D
2015-10-31 06:29:39 +00:00
/// 8 bytes in SCSI-2, MMC-1, MMC-2, MMC-3
2015-10-30 17:11:16 +00:00
/// </summary>
public struct ModePage_0D
{
/// <summary>
/// Parameters can be saved
/// </summary>
public bool PS;
/// <summary>
/// Time the drive shall remain in hold track state after seek or read
/// </summary>
public byte InactivityTimerMultiplier;
/// <summary>
/// Seconds per Minute
/// </summary>
public ushort SecondsPerMinute;
/// <summary>
/// Frames per Second
/// </summary>
public ushort FramesPerSecond;
}
public static ModePage_0D? DecodeModePage_0D(byte[] pageResponse)
{
2016-04-19 02:11:47 +01:00
if(pageResponse == null)
2015-10-30 17:11:16 +00:00
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x40) == 0x40)
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x3F) != 0x0D)
2015-10-30 17:11:16 +00:00
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse[1] + 2 != pageResponse.Length)
2015-10-30 17:11:16 +00:00
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse.Length < 8)
2015-10-30 17:11:16 +00:00
return null;
ModePage_0D decoded = new ModePage_0D();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.InactivityTimerMultiplier = (byte)(pageResponse[3] & 0xF);
decoded.SecondsPerMinute = (ushort)((pageResponse[4] << 8) + pageResponse[5]);
decoded.FramesPerSecond = (ushort)((pageResponse[6] << 8) + pageResponse[7]);
return decoded;
}
public static string PrettifyModePage_0D(byte[] pageResponse)
{
return PrettifyModePage_0D(DecodeModePage_0D(pageResponse));
}
public static string PrettifyModePage_0D(ModePage_0D? modePage)
{
2016-04-19 02:11:47 +01:00
if(!modePage.HasValue)
2015-10-30 17:11:16 +00:00
return null;
ModePage_0D page = modePage.Value;
StringBuilder sb = new StringBuilder();
sb.AppendLine("SCSI CD-ROM parameters page:");
2016-04-19 02:11:47 +01:00
if(page.PS)
2015-10-30 17:11:16 +00:00
sb.AppendLine("\tParameters can be saved");
2016-04-19 02:11:47 +01:00
switch(page.InactivityTimerMultiplier)
2015-10-30 17:11:16 +00:00
{
case 0:
sb.AppendLine("\tDrive will remain in track hold state a vendor-specified time after a seek or read");
2015-10-30 17:11:16 +00:00
break;
case 1:
sb.AppendLine("\tDrive will remain in track hold state 125 ms after a seek or read");
2015-10-30 17:11:16 +00:00
break;
case 2:
sb.AppendLine("\tDrive will remain in track hold state 250 ms after a seek or read");
2015-10-30 17:11:16 +00:00
break;
case 3:
sb.AppendLine("\tDrive will remain in track hold state 500 ms after a seek or read");
2015-10-30 17:11:16 +00:00
break;
case 4:
sb.AppendLine("\tDrive will remain in track hold state 1 second after a seek or read");
2015-10-30 17:11:16 +00:00
break;
case 5:
sb.AppendLine("\tDrive will remain in track hold state 2 seconds after a seek or read");
2015-10-30 17:11:16 +00:00
break;
case 6:
sb.AppendLine("\tDrive will remain in track hold state 4 seconds after a seek or read");
2015-10-30 17:11:16 +00:00
break;
case 7:
sb.AppendLine("\tDrive will remain in track hold state 8 seconds after a seek or read");
2015-10-30 17:11:16 +00:00
break;
case 8:
sb.AppendLine("\tDrive will remain in track hold state 16 seconds after a seek or read");
2015-10-30 17:11:16 +00:00
break;
case 9:
sb.AppendLine("\tDrive will remain in track hold state 32 seconds after a seek or read");
2015-10-30 17:11:16 +00:00
break;
case 10:
sb.AppendLine("\tDrive will remain in track hold state 1 minute after a seek or read");
2015-10-30 17:11:16 +00:00
break;
case 11:
sb.AppendLine("\tDrive will remain in track hold state 2 minutes after a seek or read");
2015-10-30 17:11:16 +00:00
break;
case 12:
sb.AppendLine("\tDrive will remain in track hold state 4 minutes after a seek or read");
2015-10-30 17:11:16 +00:00
break;
case 13:
sb.AppendLine("\tDrive will remain in track hold state 8 minutes after a seek or read");
2015-10-30 17:11:16 +00:00
break;
case 14:
sb.AppendLine("\tDrive will remain in track hold state 16 minutes after a seek or read");
2015-10-30 17:11:16 +00:00
break;
case 15:
sb.AppendLine("\tDrive will remain in track hold state 32 minutes after a seek or read");
2015-10-30 17:11:16 +00:00
break;
}
2016-04-19 02:11:47 +01:00
if(page.SecondsPerMinute > 0)
sb.AppendFormat("\tEach minute has {0} seconds", page.SecondsPerMinute).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.FramesPerSecond > 0)
sb.AppendFormat("\tEach second has {0} frames", page.FramesPerSecond).AppendLine();
2015-10-30 17:11:16 +00:00
return sb.ToString();
}
2015-10-30 17:11:16 +00:00
#endregion Mode Page 0x0D: CD-ROM parameteres page
#region Mode Page 0x01: Read error recovery page for MultiMedia Devices
/// <summary>
/// Read error recovery page for MultiMedia Devices
/// Page code 0x01
/// 8 bytes in SCSI-2, MMC-1
2015-10-31 06:29:39 +00:00
/// 12 bytes in MMC-2, MMC-3
/// </summary>
public struct ModePage_01_MMC
{
/// <summary>
/// Parameters can be saved
/// </summary>
public bool PS;
/// <summary>
/// Error recovery parameter
/// </summary>
public byte Parameter;
/// <summary>
/// How many times to retry a read operation
/// </summary>
public byte ReadRetryCount;
2015-10-31 06:29:39 +00:00
/// <summary>
/// How many times to retry a write operation
/// </summary>
public byte WriteRetryCount;
/// <summary>
/// Maximum time in ms to use in data error recovery procedures
/// </summary>
public ushort RecoveryTimeLimit;
}
public static ModePage_01_MMC? DecodeModePage_01_MMC(byte[] pageResponse)
{
2016-04-19 02:11:47 +01:00
if(pageResponse == null)
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x40) == 0x40)
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x3F) != 0x01)
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse.Length < 8)
return null;
ModePage_01_MMC decoded = new ModePage_01_MMC();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.Parameter = pageResponse[2];
decoded.ReadRetryCount = pageResponse[3];
2016-04-19 02:11:47 +01:00
if(pageResponse.Length < 12)
2015-10-31 06:29:39 +00:00
return decoded;
decoded.WriteRetryCount = pageResponse[8];
decoded.RecoveryTimeLimit = (ushort)((pageResponse[10] << 8) + pageResponse[11]);
return decoded;
}
public static string PrettifyModePage_01_MMC(byte[] pageResponse)
{
return PrettifyModePage_01_MMC(DecodeModePage_01_MMC(pageResponse));
}
public static string PrettifyModePage_01_MMC(ModePage_01_MMC? modePage)
{
2016-04-19 02:11:47 +01:00
if(!modePage.HasValue)
return null;
ModePage_01_MMC page = modePage.Value;
StringBuilder sb = new StringBuilder();
sb.AppendLine("SCSI Read error recovery page for MultiMedia Devices:");
2016-04-19 02:11:47 +01:00
if(page.PS)
sb.AppendLine("\tParameters can be saved");
2016-04-19 02:11:47 +01:00
if(page.ReadRetryCount > 0)
sb.AppendFormat("\tDrive will repeat read operations {0} times", page.ReadRetryCount).AppendLine();
2016-04-19 02:11:47 +01:00
string AllUsed = "\tAll available recovery procedures will be used.\n";
string CIRCRetriesUsed = "\tOnly retries and CIRC are used.\n";
string RetriesUsed = "\tOnly retries are used.\n";
string RecoveredNotReported = "\tRecovered errors will not be reported.\n";
string RecoveredReported = "\tRecovered errors will be reported.\n";
string RecoveredAbort = "\tRecovered errors will be reported and aborted with CHECK CONDITION.\n";
string UnrecECCAbort = "\tUnrecovered ECC errors will return CHECK CONDITION.";
string UnrecCIRCAbort = "\tUnrecovered CIRC errors will return CHECK CONDITION.";
string UnrecECCNotAbort = "\tUnrecovered ECC errors will not abort the transfer.";
string UnrecCIRCNotAbort = "\tUnrecovered CIRC errors will not abort the transfer.";
string UnrecECCAbortData = "\tUnrecovered ECC errors will return CHECK CONDITION and the uncorrected data.";
string UnrecCIRCAbortData = "\tUnrecovered CIRC errors will return CHECK CONDITION and the uncorrected data.";
2016-04-19 02:11:47 +01:00
switch(page.Parameter)
{
case 0x00:
sb.AppendLine(AllUsed + RecoveredNotReported + UnrecECCAbort);
break;
case 0x01:
sb.AppendLine(CIRCRetriesUsed + RecoveredNotReported + UnrecCIRCAbort);
break;
case 0x04:
sb.AppendLine(AllUsed + RecoveredReported + UnrecECCAbort);
break;
case 0x05:
sb.AppendLine(CIRCRetriesUsed + RecoveredReported + UnrecCIRCAbort);
break;
case 0x06:
sb.AppendLine(AllUsed + RecoveredAbort + UnrecECCAbort);
break;
case 0x07:
sb.AppendLine(RetriesUsed + RecoveredAbort + UnrecCIRCAbort);
break;
case 0x10:
sb.AppendLine(AllUsed + RecoveredNotReported + UnrecECCNotAbort);
break;
case 0x11:
sb.AppendLine(CIRCRetriesUsed + RecoveredNotReported + UnrecCIRCNotAbort);
break;
case 0x14:
sb.AppendLine(AllUsed + RecoveredReported + UnrecECCNotAbort);
break;
case 0x15:
sb.AppendLine(CIRCRetriesUsed + RecoveredReported + UnrecCIRCNotAbort);
break;
case 0x20:
sb.AppendLine(AllUsed + RecoveredNotReported + UnrecECCAbortData);
break;
case 0x21:
sb.AppendLine(CIRCRetriesUsed + RecoveredNotReported + UnrecCIRCAbortData);
break;
case 0x24:
sb.AppendLine(AllUsed + RecoveredReported + UnrecECCAbortData);
break;
case 0x25:
sb.AppendLine(CIRCRetriesUsed + RecoveredReported + UnrecCIRCAbortData);
break;
case 0x26:
sb.AppendLine(AllUsed + RecoveredAbort + UnrecECCAbortData);
break;
case 0x27:
sb.AppendLine(RetriesUsed + RecoveredAbort + UnrecCIRCAbortData);
break;
case 0x30:
goto case 0x10;
case 0x31:
goto case 0x11;
case 0x34:
goto case 0x14;
case 0x35:
goto case 0x15;
default:
sb.AppendFormat("Unknown recovery parameter 0x{0:X2}", page.Parameter).AppendLine();
break;
}
2016-04-19 02:11:47 +01:00
if(page.WriteRetryCount > 0)
2015-10-31 06:29:39 +00:00
sb.AppendFormat("\tDrive will repeat write operations {0} times", page.WriteRetryCount).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.RecoveryTimeLimit > 0)
2015-10-31 06:29:39 +00:00
sb.AppendFormat("\tDrive will employ a maximum of {0} ms to recover data", page.RecoveryTimeLimit).AppendLine();
2016-04-19 02:11:47 +01:00
return sb.ToString();
}
#endregion Mode Page 0x01: Read error recovery page for MultiMedia Devices
#region Mode Page 0x07: Verify error recovery page for MultiMedia Devices
/// <summary>
/// Verify error recovery page for MultiMedia Devices
/// Page code 0x07
/// 8 bytes in SCSI-2, MMC-1
/// </summary>
public struct ModePage_07_MMC
{
/// <summary>
/// Parameters can be saved
/// </summary>
public bool PS;
/// <summary>
/// Error recovery parameter
/// </summary>
public byte Parameter;
/// <summary>
/// How many times to retry a verify operation
/// </summary>
public byte VerifyRetryCount;
}
public static ModePage_07_MMC? DecodeModePage_07_MMC(byte[] pageResponse)
{
2016-04-19 02:11:47 +01:00
if(pageResponse == null)
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x40) == 0x40)
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x3F) != 0x07)
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse.Length < 8)
return null;
ModePage_07_MMC decoded = new ModePage_07_MMC();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.Parameter = pageResponse[2];
decoded.VerifyRetryCount = pageResponse[3];
return decoded;
}
public static string PrettifyModePage_07_MMC(byte[] pageResponse)
{
return PrettifyModePage_07_MMC(DecodeModePage_07_MMC(pageResponse));
}
public static string PrettifyModePage_07_MMC(ModePage_07_MMC? modePage)
{
2016-04-19 02:11:47 +01:00
if(!modePage.HasValue)
return null;
ModePage_07_MMC page = modePage.Value;
StringBuilder sb = new StringBuilder();
sb.AppendLine("SCSI Verify error recovery page for MultiMedia Devices:");
2016-04-19 02:11:47 +01:00
if(page.PS)
sb.AppendLine("\tParameters can be saved");
2016-04-19 02:11:47 +01:00
if(page.VerifyRetryCount > 0)
sb.AppendFormat("\tDrive will repeat verify operations {0} times", page.VerifyRetryCount).AppendLine();
string AllUsed = "\tAll available recovery procedures will be used.\n";
string CIRCRetriesUsed = "\tOnly retries and CIRC are used.\n";
string RetriesUsed = "\tOnly retries are used.\n";
string RecoveredNotReported = "\tRecovered errors will not be reported.\n";
string RecoveredReported = "\tRecovered errors will be reported.\n";
string RecoveredAbort = "\tRecovered errors will be reported and aborted with CHECK CONDITION.\n";
string UnrecECCAbort = "\tUnrecovered ECC errors will return CHECK CONDITION.";
string UnrecCIRCAbort = "\tUnrecovered CIRC errors will return CHECK CONDITION.";
string UnrecECCNotAbort = "\tUnrecovered ECC errors will not abort the transfer.";
string UnrecCIRCNotAbort = "\tUnrecovered CIRC errors will not abort the transfer.";
string UnrecECCAbortData = "\tUnrecovered ECC errors will return CHECK CONDITION and the uncorrected data.";
string UnrecCIRCAbortData = "\tUnrecovered CIRC errors will return CHECK CONDITION and the uncorrected data.";
2016-04-19 02:11:47 +01:00
switch(page.Parameter)
{
case 0x00:
sb.AppendLine(AllUsed + RecoveredNotReported + UnrecECCAbort);
break;
case 0x01:
sb.AppendLine(CIRCRetriesUsed + RecoveredNotReported + UnrecCIRCAbort);
break;
case 0x04:
sb.AppendLine(AllUsed + RecoveredReported + UnrecECCAbort);
break;
case 0x05:
sb.AppendLine(CIRCRetriesUsed + RecoveredReported + UnrecCIRCAbort);
break;
case 0x06:
sb.AppendLine(AllUsed + RecoveredAbort + UnrecECCAbort);
break;
case 0x07:
sb.AppendLine(RetriesUsed + RecoveredAbort + UnrecCIRCAbort);
break;
case 0x10:
sb.AppendLine(AllUsed + RecoveredNotReported + UnrecECCNotAbort);
break;
case 0x11:
sb.AppendLine(CIRCRetriesUsed + RecoveredNotReported + UnrecCIRCNotAbort);
break;
case 0x14:
sb.AppendLine(AllUsed + RecoveredReported + UnrecECCNotAbort);
break;
case 0x15:
sb.AppendLine(CIRCRetriesUsed + RecoveredReported + UnrecCIRCNotAbort);
break;
case 0x20:
sb.AppendLine(AllUsed + RecoveredNotReported + UnrecECCAbortData);
break;
case 0x21:
sb.AppendLine(CIRCRetriesUsed + RecoveredNotReported + UnrecCIRCAbortData);
break;
case 0x24:
sb.AppendLine(AllUsed + RecoveredReported + UnrecECCAbortData);
break;
case 0x25:
sb.AppendLine(CIRCRetriesUsed + RecoveredReported + UnrecCIRCAbortData);
break;
case 0x26:
sb.AppendLine(AllUsed + RecoveredAbort + UnrecECCAbortData);
break;
case 0x27:
sb.AppendLine(RetriesUsed + RecoveredAbort + UnrecCIRCAbortData);
break;
case 0x30:
goto case 0x10;
case 0x31:
goto case 0x11;
case 0x34:
goto case 0x14;
case 0x35:
goto case 0x15;
default:
sb.AppendFormat("Unknown recovery parameter 0x{0:X2}", page.Parameter).AppendLine();
break;
}
return sb.ToString();
}
#endregion Mode Page 0x07: Verify error recovery page for MultiMedia Devices
2015-10-30 17:45:52 +00:00
#region Mode Page 0x06: Optical memory page
2015-10-30 17:45:52 +00:00
/// <summary>
/// Optical memory page
/// Page code 0x06
/// 4 bytes in SCSI-2
/// </summary>
public struct ModePage_06
{
/// <summary>
/// Parameters can be saved
/// </summary>
public bool PS;
/// <summary>
/// Report updated block read
/// </summary>
public bool RUBR;
}
public static ModePage_06? DecodeModePage_06(byte[] pageResponse)
{
2016-04-19 02:11:47 +01:00
if(pageResponse == null)
2015-10-30 17:45:52 +00:00
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x40) == 0x40)
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x3F) != 0x06)
2015-10-30 17:45:52 +00:00
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse[1] + 2 != pageResponse.Length)
2015-10-30 17:45:52 +00:00
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse.Length < 4)
2015-10-30 17:45:52 +00:00
return null;
ModePage_06 decoded = new ModePage_06();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.RUBR |= (pageResponse[2] & 0x01) == 0x01;
return decoded;
}
public static string PrettifyModePage_06(byte[] pageResponse)
{
return PrettifyModePage_06(DecodeModePage_06(pageResponse));
}
public static string PrettifyModePage_06(ModePage_06? modePage)
{
2016-04-19 02:11:47 +01:00
if(!modePage.HasValue)
2015-10-30 17:45:52 +00:00
return null;
ModePage_06 page = modePage.Value;
StringBuilder sb = new StringBuilder();
sb.AppendLine("SCSI optical memory:");
2016-04-19 02:11:47 +01:00
if(page.PS)
2015-10-30 17:45:52 +00:00
sb.AppendLine("\tParameters can be saved");
2016-04-19 02:11:47 +01:00
if(page.RUBR)
2015-10-30 17:45:52 +00:00
sb.AppendLine("\tOn reading an updated block drive will return RECOVERED ERROR");
return sb.ToString();
}
2015-10-30 17:45:52 +00:00
#endregion Mode Page 0x06: Optical memory page
2015-10-30 18:35:56 +00:00
#region Mode Page 0x2A: CD-ROM capabilities page
2015-10-30 18:35:56 +00:00
/// <summary>
/// CD-ROM capabilities page
/// Page code 0x2A
/// 16 bytes in OB-U0077C
2015-10-30 19:03:40 +00:00
/// 20 bytes in SFF-8020i
/// 22 bytes in MMC-1
2015-10-31 06:07:07 +00:00
/// 26 bytes in MMC-2
2015-10-31 06:29:39 +00:00
/// Variable bytes in MMC-3
2015-10-30 18:35:56 +00:00
/// </summary>
public struct ModePage_2A
{
/// <summary>
/// Parameters can be saved
/// </summary>
public bool PS;
/// <summary>
/// Drive supports multi-session and/or Photo-CD
/// </summary>
public bool MultiSession;
/// <summary>
/// Drive is capable of reading sectors in Mode 2 Form 2 format
/// </summary>
public bool Mode2Form2;
/// <summary>
/// Drive is capable of reading sectors in Mode 2 Form 1 format
/// </summary>
public bool Mode2Form1;
/// <summary>
/// Drive is capable of playing audio
/// </summary>
public bool AudioPlay;
/// <summary>
/// Drive can return the ISRC
/// </summary>
public bool ISRC;
/// <summary>
/// Drive can return the media catalogue number
/// </summary>
public bool UPC;
/// <summary>
/// Drive can return C2 pointers
/// </summary>
public bool C2Pointer;
/// <summary>
/// Drive can read, deinterlave and correct R-W subchannels
/// </summary>
public bool DeinterlaveSubchannel;
/// <summary>
/// Drive can read interleaved and uncorrected R-W subchannels
/// </summary>
public bool Subchannel;
/// <summary>
/// Drive can continue from a loss of streaming on audio reading
/// </summary>
public bool AccurateCDDA;
/// <summary>
/// Audio can be read as digital data
/// </summary>
public bool CDDACommand;
/// <summary>
/// Loading Mechanism Type
/// </summary>
public byte LoadingMechanism;
/// <summary>
/// Drive can eject discs
/// </summary>
public bool Eject;
/// <summary>
/// Drive's optional prevent jumper status
/// </summary>
public bool PreventJumper;
/// <summary>
/// Current lock status
/// </summary>
public bool LockState;
/// <summary>
/// Drive can lock media
/// </summary>
public bool Lock;
/// <summary>
/// Each channel can be muted independently
/// </summary>
public bool SeparateChannelMute;
/// <summary>
/// Each channel's volume can be controlled independently
/// </summary>
public bool SeparateChannelVolume;
/// <summary>
/// Maximum drive speed in Kbytes/second
/// </summary>
public ushort MaximumSpeed;
/// <summary>
/// Supported volume levels
/// </summary>
public ushort SupportedVolumeLevels;
/// <summary>
/// Buffer size in Kbytes
/// </summary>
public ushort BufferSize;
/// <summary>
/// Current drive speed in Kbytes/second
/// </summary>
public ushort CurrentSpeed;
2015-10-30 19:03:40 +00:00
public bool Method2;
public bool ReadCDRW;
public bool ReadCDR;
public bool WriteCDRW;
public bool WriteCDR;
public bool DigitalPort2;
public bool DigitalPort1;
public bool Composite;
public bool SSS;
public bool SDP;
public byte Length;
public bool LSBF;
public bool RCK;
public bool BCK;
public bool TestWrite;
public ushort MaxWriteSpeed;
public ushort CurrentWriteSpeed;
2015-10-31 05:43:36 +00:00
public bool ReadBarcode;
2015-10-31 06:07:07 +00:00
public bool ReadDVDRAM;
public bool ReadDVDR;
public bool ReadDVDROM;
public bool WriteDVDRAM;
public bool WriteDVDR;
public bool LeadInPW;
public bool SCC;
public ushort CMRSupported;
2015-10-31 06:29:39 +00:00
public bool BUF;
public byte RotationControlSelected;
public ushort CurrentWriteSpeedSelected;
public ModePage_2A_WriteDescriptor[] WriteSpeedPerformanceDescriptors;
}
public struct ModePage_2A_WriteDescriptor
{
public byte RotationControl;
public ushort WriteSpeed;
2015-10-30 18:35:56 +00:00
}
public static ModePage_2A? DecodeModePage_2A(byte[] pageResponse)
{
2016-04-19 02:11:47 +01:00
if(pageResponse == null)
2015-10-30 18:35:56 +00:00
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x40) == 0x40)
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x3F) != 0x2A)
2015-10-30 18:35:56 +00:00
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse[1] + 2 != pageResponse.Length)
2015-10-30 18:35:56 +00:00
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse.Length < 16)
2015-10-30 18:35:56 +00:00
return null;
ModePage_2A decoded = new ModePage_2A();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.AudioPlay |= (pageResponse[4] & 0x01) == 0x01;
decoded.Mode2Form1 |= (pageResponse[4] & 0x10) == 0x10;
decoded.Mode2Form2 |= (pageResponse[4] & 0x20) == 0x20;
decoded.MultiSession |= (pageResponse[4] & 0x40) == 0x40;
decoded.CDDACommand |= (pageResponse[5] & 0x01) == 0x01;
decoded.AccurateCDDA |= (pageResponse[5] & 0x02) == 0x02;
decoded.Subchannel |= (pageResponse[5] & 0x04) == 0x04;
decoded.DeinterlaveSubchannel |= (pageResponse[5] & 0x08) == 0x08;
decoded.C2Pointer |= (pageResponse[5] & 0x10) == 0x10;
decoded.UPC |= (pageResponse[5] & 0x20) == 0x20;
decoded.ISRC |= (pageResponse[5] & 0x40) == 0x40;
decoded.LoadingMechanism = (byte)((pageResponse[6] & 0xE0) >> 5);
decoded.Lock |= (pageResponse[6] & 0x01) == 0x01;
decoded.LockState |= (pageResponse[6] & 0x02) == 0x02;
decoded.PreventJumper |= (pageResponse[6] & 0x04) == 0x04;
decoded.Eject |= (pageResponse[6] & 0x08) == 0x08;
decoded.SeparateChannelVolume |= (pageResponse[7] & 0x01) == 0x01;
decoded.SeparateChannelMute |= (pageResponse[7] & 0x02) == 0x02;
decoded.MaximumSpeed = (ushort)((pageResponse[8] << 8) + pageResponse[9]);
decoded.SupportedVolumeLevels = (ushort)((pageResponse[10] << 8) + pageResponse[11]);
decoded.BufferSize = (ushort)((pageResponse[12] << 8) + pageResponse[13]);
decoded.CurrentSpeed = (ushort)((pageResponse[14] << 8) + pageResponse[15]);
2016-04-19 02:11:47 +01:00
if(pageResponse.Length < 20)
2015-10-30 19:03:40 +00:00
return decoded;
decoded.Method2 |= (pageResponse[2] & 0x04) == 0x04;
decoded.ReadCDRW |= (pageResponse[2] & 0x02) == 0x02;
decoded.ReadCDR |= (pageResponse[2] & 0x01) == 0x01;
decoded.WriteCDRW |= (pageResponse[3] & 0x02) == 0x02;
decoded.WriteCDR |= (pageResponse[3] & 0x01) == 0x01;
decoded.Composite |= (pageResponse[4] & 0x02) == 0x02;
decoded.DigitalPort1 |= (pageResponse[4] & 0x04) == 0x04;
decoded.DigitalPort2 |= (pageResponse[4] & 0x08) == 0x08;
decoded.SDP |= (pageResponse[7] & 0x04) == 0x04;
decoded.SSS |= (pageResponse[7] & 0x08) == 0x08;
decoded.Length = (byte)((pageResponse[17] & 0x30) >> 4);
decoded.LSBF |= (pageResponse[17] & 0x08) == 0x08;
decoded.RCK |= (pageResponse[17] & 0x04) == 0x04;
decoded.BCK |= (pageResponse[17] & 0x02) == 0x02;
2016-04-19 02:11:47 +01:00
if(pageResponse.Length < 22)
return decoded;
decoded.TestWrite |= (pageResponse[3] & 0x04) == 0x04;
decoded.MaxWriteSpeed = (ushort)((pageResponse[18] << 8) + pageResponse[19]);
decoded.CurrentWriteSpeed = (ushort)((pageResponse[20] << 8) + pageResponse[21]);
2015-10-31 05:43:36 +00:00
decoded.ReadBarcode |= (pageResponse[5] & 0x80) == 0x80;
2016-04-19 02:11:47 +01:00
if(pageResponse.Length < 26)
2015-10-31 06:07:07 +00:00
return decoded;
decoded.ReadDVDRAM |= (pageResponse[2] & 0x20) == 0x20;
decoded.ReadDVDR |= (pageResponse[2] & 0x10) == 0x10;
decoded.ReadDVDROM |= (pageResponse[2] & 0x08) == 0x08;
decoded.WriteDVDRAM |= (pageResponse[3] & 0x20) == 0x20;
decoded.WriteDVDR |= (pageResponse[3] & 0x10) == 0x10;
decoded.LeadInPW |= (pageResponse[3] & 0x20) == 0x20;
decoded.SCC |= (pageResponse[3] & 0x10) == 0x10;
decoded.CMRSupported = (ushort)((pageResponse[22] << 8) + pageResponse[23]);
2016-04-19 02:11:47 +01:00
if(pageResponse.Length < 32)
2015-10-31 06:29:39 +00:00
return decoded;
decoded.BUF |= (pageResponse[4] & 0x80) == 0x80;
decoded.RotationControlSelected = (byte)(pageResponse[27] & 0x03);
decoded.CurrentWriteSpeedSelected = (ushort)((pageResponse[28] << 8) + pageResponse[29]);
ushort descriptors = (ushort)((pageResponse[30] << 8) + pageResponse[31]);
decoded.WriteSpeedPerformanceDescriptors = new ModePage_2A_WriteDescriptor[descriptors];
2016-04-19 02:11:47 +01:00
for(int i = 0; i < descriptors; i++)
2015-10-31 06:29:39 +00:00
{
decoded.WriteSpeedPerformanceDescriptors[i] = new ModePage_2A_WriteDescriptor();
decoded.WriteSpeedPerformanceDescriptors[i].RotationControl = (byte)(pageResponse[1 + 32 + i * 4] & 0x07);
decoded.WriteSpeedPerformanceDescriptors[i].WriteSpeed = (ushort)((pageResponse[2 + 32 + i * 4] << 8) + pageResponse[3 + 32 + i * 4]);
}
2015-10-30 18:35:56 +00:00
return decoded;
}
public static string PrettifyModePage_2A(byte[] pageResponse)
{
return PrettifyModePage_2A(DecodeModePage_2A(pageResponse));
}
public static string PrettifyModePage_2A(ModePage_2A? modePage)
{
2016-04-19 02:11:47 +01:00
if(!modePage.HasValue)
2015-10-30 18:35:56 +00:00
return null;
ModePage_2A page = modePage.Value;
StringBuilder sb = new StringBuilder();
sb.AppendLine("SCSI CD-ROM capabilities page:");
2016-04-19 02:11:47 +01:00
if(page.PS)
2015-10-30 18:35:56 +00:00
sb.AppendLine("\tParameters can be saved");
2016-04-19 02:11:47 +01:00
if(page.AudioPlay)
2015-10-30 18:35:56 +00:00
sb.AppendLine("\tDrive can play audio");
2016-04-19 02:11:47 +01:00
if(page.Mode2Form1)
2015-10-30 18:35:56 +00:00
sb.AppendLine("\tDrive can read sectors in Mode 2 Form 1 format");
2016-04-19 02:11:47 +01:00
if(page.Mode2Form2)
2015-10-30 18:35:56 +00:00
sb.AppendLine("\tDrive can read sectors in Mode 2 Form 2 format");
2016-04-19 02:11:47 +01:00
if(page.MultiSession)
2015-10-30 18:35:56 +00:00
sb.AppendLine("\tDrive supports multi-session discs and/or Photo-CD");
2016-04-19 02:11:47 +01:00
if(page.CDDACommand)
2015-10-30 18:35:56 +00:00
sb.AppendLine("\tDrive can read digital audio");
2016-04-19 02:11:47 +01:00
if(page.AccurateCDDA)
2015-10-30 18:35:56 +00:00
sb.AppendLine("\tDrive can continue from streaming loss");
2016-04-19 02:11:47 +01:00
if(page.Subchannel)
2015-10-30 18:35:56 +00:00
sb.AppendLine("\tDrive can read uncorrected and interleaved R-W subchannels");
2016-04-19 02:11:47 +01:00
if(page.DeinterlaveSubchannel)
2015-10-30 18:35:56 +00:00
sb.AppendLine("\tDrive can read, deinterleave and correct R-W subchannels");
2016-04-19 02:11:47 +01:00
if(page.C2Pointer)
2015-10-30 18:35:56 +00:00
sb.AppendLine("\tDrive supports C2 pointers");
2016-04-19 02:11:47 +01:00
if(page.UPC)
2015-10-30 18:35:56 +00:00
sb.AppendLine("\tDrive can read Media Catalogue Number");
2016-04-19 02:11:47 +01:00
if(page.ISRC)
2015-10-30 18:35:56 +00:00
sb.AppendLine("\tDrive can read ISRC");
2016-04-19 02:11:47 +01:00
switch(page.LoadingMechanism)
2015-10-30 18:35:56 +00:00
{
case 0:
sb.AppendLine("\tDrive uses media caddy");
break;
case 1:
sb.AppendLine("\tDrive uses a tray");
break;
case 2:
sb.AppendLine("\tDrive is pop-up");
break;
2015-10-30 19:03:40 +00:00
case 4:
sb.AppendLine("\tDrive is a changer with individually changeable discs");
break;
case 5:
sb.AppendLine("\tDrive is a changer using cartridges");
break;
2015-10-30 18:35:56 +00:00
default:
sb.AppendFormat("\tDrive uses unknown loading mechanism type {0}", page.LoadingMechanism).AppendLine();
break;
}
2016-04-19 02:11:47 +01:00
if(page.Lock)
2015-10-30 18:35:56 +00:00
sb.AppendLine("\tDrive can lock media");
2016-04-19 02:11:47 +01:00
if(page.PreventJumper)
2015-10-30 18:35:56 +00:00
{
sb.AppendLine("\tDrive power ups locked");
2016-04-19 02:11:47 +01:00
if(page.LockState)
2015-10-30 18:35:56 +00:00
sb.AppendLine("\tDrive is locked, media cannot be ejected or inserted");
else
sb.AppendLine("\tDrive is not locked, media can be ejected and inserted");
}
else
{
2016-04-19 02:11:47 +01:00
if(page.LockState)
2015-10-30 18:35:56 +00:00
sb.AppendLine("\tDrive is locked, media cannot be ejected, but if empty, can be inserted");
else
sb.AppendLine("\tDrive is not locked, media can be ejected and inserted");
}
2016-04-19 02:11:47 +01:00
if(page.Eject)
2015-10-30 18:35:56 +00:00
sb.AppendLine("\tDrive can eject media");
2016-04-19 02:11:47 +01:00
if(page.SeparateChannelMute)
2015-10-30 18:35:56 +00:00
sb.AppendLine("\tEach channel can be muted independently");
2016-04-19 02:11:47 +01:00
if(page.SeparateChannelVolume)
2015-10-30 18:35:56 +00:00
sb.AppendLine("\tEach channel's volume can be controlled independently");
2016-04-19 02:11:47 +01:00
if(page.SupportedVolumeLevels > 0)
2015-10-30 18:35:56 +00:00
sb.AppendFormat("\tDrive supports {0} volume levels", page.SupportedVolumeLevels).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.BufferSize > 0)
2015-10-30 18:35:56 +00:00
sb.AppendFormat("\tDrive has {0} Kbyte of buffer", page.BufferSize).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.MaximumSpeed > 0)
sb.AppendFormat("\tDrive's maximum reading speed is {0} Kbyte/sec.", page.MaximumSpeed).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.CurrentSpeed > 0)
sb.AppendFormat("\tDrive's current reading speed is {0} Kbyte/sec.", page.CurrentSpeed).AppendLine();
2015-10-30 18:35:56 +00:00
2016-04-19 02:11:47 +01:00
if(page.ReadCDR)
2015-10-30 19:03:40 +00:00
{
2016-04-19 02:11:47 +01:00
if(page.WriteCDR)
2015-10-30 19:03:40 +00:00
sb.AppendLine("\tDrive can read and write CD-R");
else
sb.AppendLine("\tDrive can read CD-R");
2016-04-19 02:11:47 +01:00
if(page.Method2)
2015-10-30 19:03:40 +00:00
sb.AppendLine("\tDrive supports reading CD-R packet media");
}
2016-04-19 02:11:47 +01:00
if(page.ReadCDRW)
2015-10-30 19:03:40 +00:00
{
2016-04-19 02:11:47 +01:00
if(page.WriteCDRW)
2015-10-30 19:03:40 +00:00
sb.AppendLine("\tDrive can read and write CD-RW");
else
sb.AppendLine("\tDrive can read CD-RW");
}
2016-04-19 02:11:47 +01:00
if(page.ReadDVDROM)
2015-10-31 06:07:07 +00:00
sb.AppendLine("\tDrive can read DVD-ROM");
2016-04-19 02:11:47 +01:00
if(page.ReadDVDR)
2015-10-31 06:07:07 +00:00
{
2016-04-19 02:11:47 +01:00
if(page.WriteDVDR)
2015-10-31 06:07:07 +00:00
sb.AppendLine("\tDrive can read and write DVD-R");
else
sb.AppendLine("\tDrive can read DVD-R");
}
2016-04-19 02:11:47 +01:00
if(page.ReadDVDRAM)
2015-10-31 06:07:07 +00:00
{
2016-04-19 02:11:47 +01:00
if(page.WriteDVDRAM)
2015-10-31 06:07:07 +00:00
sb.AppendLine("\tDrive can read and write DVD-RAM");
else
sb.AppendLine("\tDrive can read DVD-RAM");
}
2016-04-19 02:11:47 +01:00
if(page.Composite)
2015-10-30 19:03:40 +00:00
sb.AppendLine("\tDrive can deliver a compositve audio and video data stream");
2016-04-19 02:11:47 +01:00
if(page.DigitalPort1)
2015-10-30 19:03:40 +00:00
sb.AppendLine("\tDrive supports IEC-958 digital output on port 1");
2016-04-19 02:11:47 +01:00
if(page.DigitalPort2)
2015-10-30 19:03:40 +00:00
sb.AppendLine("\tDrive supports IEC-958 digital output on port 2");
2016-04-19 02:11:47 +01:00
if(page.SDP)
2015-10-30 19:03:40 +00:00
sb.AppendLine("\tDrive contains a changer that can report the exact contents of the slots");
2016-04-19 02:11:47 +01:00
if(page.CurrentWriteSpeedSelected > 0)
2015-10-31 06:29:39 +00:00
{
2016-04-19 02:11:47 +01:00
if(page.RotationControlSelected == 0)
2015-10-31 06:29:39 +00:00
sb.AppendFormat("\tDrive's current writing speed is {0} Kbyte/sec. in CLV mode", page.CurrentWriteSpeedSelected).AppendLine();
2016-04-19 02:11:47 +01:00
else if(page.RotationControlSelected == 1)
2015-10-31 06:29:39 +00:00
sb.AppendFormat("\tDrive's current writing speed is {0} Kbyte/sec. in pure CAV mode", page.CurrentWriteSpeedSelected).AppendLine();
}
else
{
2016-04-19 02:11:47 +01:00
if(page.MaxWriteSpeed > 0)
2015-10-31 06:29:39 +00:00
sb.AppendFormat("\tDrive's maximum writing speed is {0} Kbyte/sec.", page.MaxWriteSpeed).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.CurrentWriteSpeed > 0)
2015-10-31 06:29:39 +00:00
sb.AppendFormat("\tDrive's current writing speed is {0} Kbyte/sec.", page.CurrentWriteSpeed).AppendLine();
}
* commandline: * DiscImageChef.Settings/Settings.cs: * DiscImageChef.Settings/docs/README.txt: * DiscImageChef.Settings/packages.config: * DiscImageChef.Settings/docs/LICENSE.txt: * DiscImageChef.Settings/docs/ChangeLog.txt: * DiscImageChef.Settings/docs/mono/index.xml: * DiscImageChef.Settings/docs/html/index.html: * DiscImageChef.Settings/Properties/AssemblyInfo.cs: * DiscImageChef.Settings/DiscImageChef.Settings.csproj: * DiscImageChef.Settings/docs/mono/ns-Claunia.PropertyList.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/UID.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/UID.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSSet.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/index.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSSet.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSDate.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSData.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSDate.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSData.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSArray.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSNumber.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSString.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSObject.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSArray.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSNumber.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSString.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSObject.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSDictionary.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSDictionary.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/PropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/PropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/XmlPropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/XmlPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/ASCIIPropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/ASCIIPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/BinaryPropertyListParser.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/BinaryPropertyListWriter.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/BinaryPropertyListWriter.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/BinaryPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/PropertyListFormatException.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/PropertyListFormatException.html: Added supports for settings * DiscImageChef/Commands/Configure.cs: Added support for settings. * DiscImageChef/Core/Statistics.cs: * DiscImageChef/Commands/Verify.cs: * DiscImageChef/Commands/Entropy.cs: * DiscImageChef/Commands/Formats.cs: * DiscImageChef/Commands/PrintHex.cs: * DiscImageChef/Commands/MediaInfo.cs: * DiscImageChef/Commands/Statistics.cs: Added statistics. * DiscImageChef.Decoders/SCSI/Inquiry.cs: Corrected bug on inquiry decoding. * DiscImageChef.Decoders/SCSI/Modes.cs: Corrected bug on decoding mode page 2Ah without write performance descriptors. Corrected bug when there is a vendor page 0 in mode sense decoding. * DiscImageChef.Devices/Device/Constructor.cs: Corrected detecting USB or FireWire attached CD/DVD/BD and tape drives. Try ATA identify on USB or FireWire that don't have SCSI INQUIRY. * DiscImageChef.DiscImages/CDRWin.cs: Corrected CD-ROM XA vs CD-ROM detection. * DiscImageChef.Partitions/AppleMap.cs: Corrected big endian working. Added debug output. * DiscImageChef.sln: Added supports for settings. * DiscImageChef/Commands/Decode.cs: * DiscImageChef/Commands/Analyze.cs: * DiscImageChef/Commands/Compare.cs: * DiscImageChef/Commands/Checksum.cs: * DiscImageChef/Commands/Benchmark.cs: * DiscImageChef/Commands/DeviceInfo.cs: * DiscImageChef/Commands/CreateSidecar.cs: Added statistics. * DiscImageChef/Commands/DeviceReport.cs: Added statistics. Correct handling empty inquiry string fields. Suppose it is not removable, til proved wrong. Corrected MODE SENSE (6/10) detection and calling order. If device is MMC type but reports neither mode page 2Ah neither GET CONFIGURATION, try all CDs (old drives work like that). Try reading Lead-In and Lead-Out in Audio CD using Audio READ CD commands. Corrected READ LONG information handling, some drives return 2s-complement in 32 bit. Upper 16 bits are ignored. Added support for DVD raw block (37856 bytes). Check READ LONG up to 36 times the cooked block size. That should be enough to detect huge blocked media (like DVD and BD) without taking ages. If READ LONG size had to be bruteforced, and debug is activated, save the result. * DiscImageChef/Commands/DumpMedia.cs: Added statistics. Corrected READ LONG information handling, some drives return 2s-complement in 32 bit. Upper 16 bits are ignored. Start trying with 64 blocks at a time. Some drives report to be able to read 255 at a time, but they really don't, they take a lot longer to read. * DiscImageChef/Commands/MediaScan.cs: Added statistics. Start trying with 64 blocks at a time. Some drives report to be able to read 255 at a time, but they really don't, they take a lot longer to read. * DiscImageChef/DiscImageChef.csproj: Added support for settings. Added statistics. * DiscImageChef/Main.cs: * DiscImageChef/Options.cs: Added support for settings. Added statistics.
2016-02-03 18:58:11 +00:00
if(page.WriteSpeedPerformanceDescriptors != null)
2015-10-31 06:29:39 +00:00
{
2016-04-19 02:11:47 +01:00
foreach(ModePage_2A_WriteDescriptor descriptor in page.WriteSpeedPerformanceDescriptors)
2015-10-31 06:29:39 +00:00
{
2016-04-19 02:11:47 +01:00
if(descriptor.WriteSpeed > 0)
* commandline: * DiscImageChef.Settings/Settings.cs: * DiscImageChef.Settings/docs/README.txt: * DiscImageChef.Settings/packages.config: * DiscImageChef.Settings/docs/LICENSE.txt: * DiscImageChef.Settings/docs/ChangeLog.txt: * DiscImageChef.Settings/docs/mono/index.xml: * DiscImageChef.Settings/docs/html/index.html: * DiscImageChef.Settings/Properties/AssemblyInfo.cs: * DiscImageChef.Settings/DiscImageChef.Settings.csproj: * DiscImageChef.Settings/docs/mono/ns-Claunia.PropertyList.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/UID.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/UID.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSSet.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/index.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSSet.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSDate.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSData.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSDate.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSData.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSArray.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSNumber.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSString.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSObject.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSArray.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSNumber.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSString.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSObject.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSDictionary.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSDictionary.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/PropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/PropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/XmlPropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/XmlPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/ASCIIPropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/ASCIIPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/BinaryPropertyListParser.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/BinaryPropertyListWriter.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/BinaryPropertyListWriter.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/BinaryPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/PropertyListFormatException.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/PropertyListFormatException.html: Added supports for settings * DiscImageChef/Commands/Configure.cs: Added support for settings. * DiscImageChef/Core/Statistics.cs: * DiscImageChef/Commands/Verify.cs: * DiscImageChef/Commands/Entropy.cs: * DiscImageChef/Commands/Formats.cs: * DiscImageChef/Commands/PrintHex.cs: * DiscImageChef/Commands/MediaInfo.cs: * DiscImageChef/Commands/Statistics.cs: Added statistics. * DiscImageChef.Decoders/SCSI/Inquiry.cs: Corrected bug on inquiry decoding. * DiscImageChef.Decoders/SCSI/Modes.cs: Corrected bug on decoding mode page 2Ah without write performance descriptors. Corrected bug when there is a vendor page 0 in mode sense decoding. * DiscImageChef.Devices/Device/Constructor.cs: Corrected detecting USB or FireWire attached CD/DVD/BD and tape drives. Try ATA identify on USB or FireWire that don't have SCSI INQUIRY. * DiscImageChef.DiscImages/CDRWin.cs: Corrected CD-ROM XA vs CD-ROM detection. * DiscImageChef.Partitions/AppleMap.cs: Corrected big endian working. Added debug output. * DiscImageChef.sln: Added supports for settings. * DiscImageChef/Commands/Decode.cs: * DiscImageChef/Commands/Analyze.cs: * DiscImageChef/Commands/Compare.cs: * DiscImageChef/Commands/Checksum.cs: * DiscImageChef/Commands/Benchmark.cs: * DiscImageChef/Commands/DeviceInfo.cs: * DiscImageChef/Commands/CreateSidecar.cs: Added statistics. * DiscImageChef/Commands/DeviceReport.cs: Added statistics. Correct handling empty inquiry string fields. Suppose it is not removable, til proved wrong. Corrected MODE SENSE (6/10) detection and calling order. If device is MMC type but reports neither mode page 2Ah neither GET CONFIGURATION, try all CDs (old drives work like that). Try reading Lead-In and Lead-Out in Audio CD using Audio READ CD commands. Corrected READ LONG information handling, some drives return 2s-complement in 32 bit. Upper 16 bits are ignored. Added support for DVD raw block (37856 bytes). Check READ LONG up to 36 times the cooked block size. That should be enough to detect huge blocked media (like DVD and BD) without taking ages. If READ LONG size had to be bruteforced, and debug is activated, save the result. * DiscImageChef/Commands/DumpMedia.cs: Added statistics. Corrected READ LONG information handling, some drives return 2s-complement in 32 bit. Upper 16 bits are ignored. Start trying with 64 blocks at a time. Some drives report to be able to read 255 at a time, but they really don't, they take a lot longer to read. * DiscImageChef/Commands/MediaScan.cs: Added statistics. Start trying with 64 blocks at a time. Some drives report to be able to read 255 at a time, but they really don't, they take a lot longer to read. * DiscImageChef/DiscImageChef.csproj: Added support for settings. Added statistics. * DiscImageChef/Main.cs: * DiscImageChef/Options.cs: Added support for settings. Added statistics.
2016-02-03 18:58:11 +00:00
{
2016-04-19 02:11:47 +01:00
if(descriptor.RotationControl == 0)
* commandline: * DiscImageChef.Settings/Settings.cs: * DiscImageChef.Settings/docs/README.txt: * DiscImageChef.Settings/packages.config: * DiscImageChef.Settings/docs/LICENSE.txt: * DiscImageChef.Settings/docs/ChangeLog.txt: * DiscImageChef.Settings/docs/mono/index.xml: * DiscImageChef.Settings/docs/html/index.html: * DiscImageChef.Settings/Properties/AssemblyInfo.cs: * DiscImageChef.Settings/DiscImageChef.Settings.csproj: * DiscImageChef.Settings/docs/mono/ns-Claunia.PropertyList.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/UID.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/UID.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSSet.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/index.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSSet.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSDate.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSData.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSDate.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSData.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSArray.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSNumber.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSString.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSObject.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSArray.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSNumber.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSString.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSObject.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSDictionary.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSDictionary.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/PropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/PropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/XmlPropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/XmlPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/ASCIIPropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/ASCIIPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/BinaryPropertyListParser.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/BinaryPropertyListWriter.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/BinaryPropertyListWriter.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/BinaryPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/PropertyListFormatException.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/PropertyListFormatException.html: Added supports for settings * DiscImageChef/Commands/Configure.cs: Added support for settings. * DiscImageChef/Core/Statistics.cs: * DiscImageChef/Commands/Verify.cs: * DiscImageChef/Commands/Entropy.cs: * DiscImageChef/Commands/Formats.cs: * DiscImageChef/Commands/PrintHex.cs: * DiscImageChef/Commands/MediaInfo.cs: * DiscImageChef/Commands/Statistics.cs: Added statistics. * DiscImageChef.Decoders/SCSI/Inquiry.cs: Corrected bug on inquiry decoding. * DiscImageChef.Decoders/SCSI/Modes.cs: Corrected bug on decoding mode page 2Ah without write performance descriptors. Corrected bug when there is a vendor page 0 in mode sense decoding. * DiscImageChef.Devices/Device/Constructor.cs: Corrected detecting USB or FireWire attached CD/DVD/BD and tape drives. Try ATA identify on USB or FireWire that don't have SCSI INQUIRY. * DiscImageChef.DiscImages/CDRWin.cs: Corrected CD-ROM XA vs CD-ROM detection. * DiscImageChef.Partitions/AppleMap.cs: Corrected big endian working. Added debug output. * DiscImageChef.sln: Added supports for settings. * DiscImageChef/Commands/Decode.cs: * DiscImageChef/Commands/Analyze.cs: * DiscImageChef/Commands/Compare.cs: * DiscImageChef/Commands/Checksum.cs: * DiscImageChef/Commands/Benchmark.cs: * DiscImageChef/Commands/DeviceInfo.cs: * DiscImageChef/Commands/CreateSidecar.cs: Added statistics. * DiscImageChef/Commands/DeviceReport.cs: Added statistics. Correct handling empty inquiry string fields. Suppose it is not removable, til proved wrong. Corrected MODE SENSE (6/10) detection and calling order. If device is MMC type but reports neither mode page 2Ah neither GET CONFIGURATION, try all CDs (old drives work like that). Try reading Lead-In and Lead-Out in Audio CD using Audio READ CD commands. Corrected READ LONG information handling, some drives return 2s-complement in 32 bit. Upper 16 bits are ignored. Added support for DVD raw block (37856 bytes). Check READ LONG up to 36 times the cooked block size. That should be enough to detect huge blocked media (like DVD and BD) without taking ages. If READ LONG size had to be bruteforced, and debug is activated, save the result. * DiscImageChef/Commands/DumpMedia.cs: Added statistics. Corrected READ LONG information handling, some drives return 2s-complement in 32 bit. Upper 16 bits are ignored. Start trying with 64 blocks at a time. Some drives report to be able to read 255 at a time, but they really don't, they take a lot longer to read. * DiscImageChef/Commands/MediaScan.cs: Added statistics. Start trying with 64 blocks at a time. Some drives report to be able to read 255 at a time, but they really don't, they take a lot longer to read. * DiscImageChef/DiscImageChef.csproj: Added support for settings. Added statistics. * DiscImageChef/Main.cs: * DiscImageChef/Options.cs: Added support for settings. Added statistics.
2016-02-03 18:58:11 +00:00
sb.AppendFormat("\tDrive supports writing at {0} Kbyte/sec. in CLV mode", descriptor.WriteSpeed).AppendLine();
2016-04-19 02:11:47 +01:00
else if(descriptor.RotationControl == 1)
* commandline: * DiscImageChef.Settings/Settings.cs: * DiscImageChef.Settings/docs/README.txt: * DiscImageChef.Settings/packages.config: * DiscImageChef.Settings/docs/LICENSE.txt: * DiscImageChef.Settings/docs/ChangeLog.txt: * DiscImageChef.Settings/docs/mono/index.xml: * DiscImageChef.Settings/docs/html/index.html: * DiscImageChef.Settings/Properties/AssemblyInfo.cs: * DiscImageChef.Settings/DiscImageChef.Settings.csproj: * DiscImageChef.Settings/docs/mono/ns-Claunia.PropertyList.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/UID.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/UID.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSSet.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/index.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSSet.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSDate.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSData.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSDate.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSData.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSArray.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSNumber.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSString.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSObject.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSArray.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSNumber.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSString.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSObject.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSDictionary.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSDictionary.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/PropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/PropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/XmlPropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/XmlPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/ASCIIPropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/ASCIIPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/BinaryPropertyListParser.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/BinaryPropertyListWriter.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/BinaryPropertyListWriter.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/BinaryPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/PropertyListFormatException.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/PropertyListFormatException.html: Added supports for settings * DiscImageChef/Commands/Configure.cs: Added support for settings. * DiscImageChef/Core/Statistics.cs: * DiscImageChef/Commands/Verify.cs: * DiscImageChef/Commands/Entropy.cs: * DiscImageChef/Commands/Formats.cs: * DiscImageChef/Commands/PrintHex.cs: * DiscImageChef/Commands/MediaInfo.cs: * DiscImageChef/Commands/Statistics.cs: Added statistics. * DiscImageChef.Decoders/SCSI/Inquiry.cs: Corrected bug on inquiry decoding. * DiscImageChef.Decoders/SCSI/Modes.cs: Corrected bug on decoding mode page 2Ah without write performance descriptors. Corrected bug when there is a vendor page 0 in mode sense decoding. * DiscImageChef.Devices/Device/Constructor.cs: Corrected detecting USB or FireWire attached CD/DVD/BD and tape drives. Try ATA identify on USB or FireWire that don't have SCSI INQUIRY. * DiscImageChef.DiscImages/CDRWin.cs: Corrected CD-ROM XA vs CD-ROM detection. * DiscImageChef.Partitions/AppleMap.cs: Corrected big endian working. Added debug output. * DiscImageChef.sln: Added supports for settings. * DiscImageChef/Commands/Decode.cs: * DiscImageChef/Commands/Analyze.cs: * DiscImageChef/Commands/Compare.cs: * DiscImageChef/Commands/Checksum.cs: * DiscImageChef/Commands/Benchmark.cs: * DiscImageChef/Commands/DeviceInfo.cs: * DiscImageChef/Commands/CreateSidecar.cs: Added statistics. * DiscImageChef/Commands/DeviceReport.cs: Added statistics. Correct handling empty inquiry string fields. Suppose it is not removable, til proved wrong. Corrected MODE SENSE (6/10) detection and calling order. If device is MMC type but reports neither mode page 2Ah neither GET CONFIGURATION, try all CDs (old drives work like that). Try reading Lead-In and Lead-Out in Audio CD using Audio READ CD commands. Corrected READ LONG information handling, some drives return 2s-complement in 32 bit. Upper 16 bits are ignored. Added support for DVD raw block (37856 bytes). Check READ LONG up to 36 times the cooked block size. That should be enough to detect huge blocked media (like DVD and BD) without taking ages. If READ LONG size had to be bruteforced, and debug is activated, save the result. * DiscImageChef/Commands/DumpMedia.cs: Added statistics. Corrected READ LONG information handling, some drives return 2s-complement in 32 bit. Upper 16 bits are ignored. Start trying with 64 blocks at a time. Some drives report to be able to read 255 at a time, but they really don't, they take a lot longer to read. * DiscImageChef/Commands/MediaScan.cs: Added statistics. Start trying with 64 blocks at a time. Some drives report to be able to read 255 at a time, but they really don't, they take a lot longer to read. * DiscImageChef/DiscImageChef.csproj: Added support for settings. Added statistics. * DiscImageChef/Main.cs: * DiscImageChef/Options.cs: Added support for settings. Added statistics.
2016-02-03 18:58:11 +00:00
sb.AppendFormat("\tDrive supports writing at is {0} Kbyte/sec. in pure CAV mode", descriptor.WriteSpeed).AppendLine();
}
2015-10-31 06:29:39 +00:00
}
}
2015-10-30 19:03:40 +00:00
2016-04-19 02:11:47 +01:00
if(page.TestWrite)
sb.AppendLine("\tDrive supports test writing");
2016-04-19 02:11:47 +01:00
if(page.ReadBarcode)
2015-10-31 05:43:36 +00:00
sb.AppendLine("\tDrive can read barcode");
2016-04-19 02:11:47 +01:00
if(page.SCC)
2015-10-31 06:07:07 +00:00
sb.AppendLine("\tDrive can read both sides of a disc");
2016-04-19 02:11:47 +01:00
if(page.LeadInPW)
2015-10-31 06:07:07 +00:00
sb.AppendLine("\tDrive an read raw R-W subchannel from the Lead-In");
2016-04-19 02:11:47 +01:00
if(page.CMRSupported == 1)
2015-10-31 06:29:39 +00:00
sb.AppendLine("\tDrive supports DVD CSS and/or DVD CPPM");
2016-04-19 02:11:47 +01:00
if(page.BUF)
2015-10-31 06:29:39 +00:00
sb.AppendLine("\tDrive supports buffer under-run free recording");
2015-10-31 06:07:07 +00:00
2015-10-30 18:35:56 +00:00
return sb.ToString();
}
2015-10-30 18:35:56 +00:00
#endregion Mode Page 0x2A: CD-ROM capabilities page
2015-10-30 19:25:19 +00:00
#region Mode Page 0x1C: Informational exceptions control page
2015-10-30 19:25:19 +00:00
/// <summary>
/// Informational exceptions control page
/// Page code 0x1C
2015-10-30 22:25:18 +00:00
/// 12 bytes in SPC-1, SPC-2, SPC-3, SPC-4
2015-10-30 19:25:19 +00:00
/// </summary>
public struct ModePage_1C
{
/// <summary>
/// Parameters can be saved
/// </summary>
public bool PS;
/// <summary>
/// Informational exception operations should not affect performance
/// </summary>
public bool Perf;
/// <summary>
/// Disable informational exception operations
/// </summary>
public bool DExcpt;
/// <summary>
/// Create a test device failure at next interval time
/// </summary>
public bool Test;
/// <summary>
/// Log informational exception conditions
/// </summary>
public bool LogErr;
/// <summary>
/// Method of reporting informational exceptions
/// </summary>
public byte MRIE;
/// <summary>
/// 100 ms period to report an informational exception condition
/// </summary>
public uint IntervalTimer;
/// <summary>
/// How many times to report informational exceptions
/// </summary>
public uint ReportCount;
/// <summary>
/// Enable background functions
/// </summary>
public bool EBF;
/// <summary>
/// Warning reporting enabled
/// </summary>
public bool EWasc;
2015-10-30 22:25:18 +00:00
/// <summary>
/// Enable reporting of background self-test errors
/// </summary>
public bool EBACKERR;
2015-10-30 19:25:19 +00:00
}
public static ModePage_1C? DecodeModePage_1C(byte[] pageResponse)
{
2016-04-19 02:11:47 +01:00
if(pageResponse == null)
2015-10-30 19:25:19 +00:00
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x40) == 0x40)
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x3F) != 0x1C)
2015-10-30 19:25:19 +00:00
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse[1] + 2 != pageResponse.Length)
2015-10-30 19:25:19 +00:00
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse.Length < 12)
2015-10-30 19:25:19 +00:00
return null;
ModePage_1C decoded = new ModePage_1C();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.Perf |= (pageResponse[2] & 0x80) == 0x80;
2015-10-30 22:25:18 +00:00
decoded.DExcpt |= (pageResponse[2] & 0x08) == 0x08;
decoded.Test |= (pageResponse[2] & 0x04) == 0x04;
decoded.LogErr |= (pageResponse[2] & 0x01) == 0x01;
2015-10-30 19:25:19 +00:00
decoded.MRIE = (byte)(pageResponse[3] & 0x0F);
decoded.IntervalTimer = (uint)((pageResponse[4] << 24) + (pageResponse[5] << 16) + (pageResponse[6] << 8) + pageResponse[7]);
decoded.ReportCount = (uint)((pageResponse[8] << 24) + (pageResponse[9] << 16) + (pageResponse[10] << 8) + pageResponse[11]);
decoded.EBF |= (pageResponse[2] & 0x20) == 0x20;
decoded.EWasc |= (pageResponse[2] & 0x10) == 0x10;
2015-10-30 22:25:18 +00:00
decoded.EBACKERR |= (pageResponse[2] & 0x02) == 0x02;
2015-10-30 19:25:19 +00:00
return decoded;
}
public static string PrettifyModePage_1C(byte[] pageResponse)
{
return PrettifyModePage_1C(DecodeModePage_1C(pageResponse));
}
public static string PrettifyModePage_1C(ModePage_1C? modePage)
{
2016-04-19 02:11:47 +01:00
if(!modePage.HasValue)
2015-10-30 19:25:19 +00:00
return null;
ModePage_1C page = modePage.Value;
StringBuilder sb = new StringBuilder();
sb.AppendLine("SCSI Informational exceptions control page:");
2016-04-19 02:11:47 +01:00
if(page.PS)
2015-10-30 19:25:19 +00:00
sb.AppendLine("\tParameters can be saved");
2016-04-19 02:11:47 +01:00
if(page.DExcpt)
2015-10-30 19:25:19 +00:00
sb.AppendLine("\tInformational exceptions are disabled");
else
{
sb.AppendLine("\tInformational exceptions are enabled");
2016-04-19 02:11:47 +01:00
switch(page.MRIE)
2015-10-30 19:25:19 +00:00
{
case 0:
sb.AppendLine("\tNo reporting of informational exception condition");
break;
case 1:
sb.AppendLine("\tAsynchronous event reporting of informational exceptions");
break;
case 2:
sb.AppendLine("\tGenerate unit attention on informational exceptions");
break;
case 3:
sb.AppendLine("\tConditionally generate recovered error on informational exceptions");
break;
case 4:
sb.AppendLine("\tUnconditionally generate recovered error on informational exceptions");
break;
case 5:
sb.AppendLine("\tGenerate no sense on informational exceptions");
break;
case 6:
sb.AppendLine("\tOnly report informational exception condition on request");
break;
default:
sb.AppendFormat("\tUnknown method of reporting {0}", page.MRIE).AppendLine();
break;
}
2016-04-19 02:11:47 +01:00
if(page.Perf)
2015-10-30 19:25:19 +00:00
sb.AppendLine("\tInformational exceptions reporting should not affect drive performance");
2016-04-19 02:11:47 +01:00
if(page.Test)
2015-10-30 19:25:19 +00:00
sb.AppendLine("\tA test informational exception will raise on next timer");
2016-04-19 02:11:47 +01:00
if(page.LogErr)
2015-10-30 19:25:19 +00:00
sb.AppendLine("\tDrive shall log informational exception conditions");
2016-04-19 02:11:47 +01:00
if(page.IntervalTimer > 0)
2015-10-30 19:25:19 +00:00
{
2016-04-19 02:11:47 +01:00
if(page.IntervalTimer == 0xFFFFFFFF)
2015-10-30 19:25:19 +00:00
sb.AppendLine("\tTimer interval is vendor-specific");
else
sb.AppendFormat("\tTimer interval is {0} ms", page.IntervalTimer * 100).AppendLine();
}
2016-04-19 02:11:47 +01:00
if(page.ReportCount > 0)
2015-10-30 19:25:19 +00:00
sb.AppendFormat("\tInformational exception conditions will be reported a maximum of {0} times", page.ReportCount);
}
2016-04-19 02:11:47 +01:00
if(page.EWasc)
sb.AppendLine("\tWarning reporting is enabled");
2016-04-19 02:11:47 +01:00
if(page.EBF)
sb.AppendLine("\tBackground functions are enabled");
2016-04-19 02:11:47 +01:00
if(page.EBACKERR)
2015-10-30 22:25:18 +00:00
sb.AppendLine("\tDrive will report background self-test errors");
2015-10-30 19:25:19 +00:00
return sb.ToString();
}
2015-10-30 19:25:19 +00:00
#endregion Mode Page 0x1C: Informational exceptions control page
2015-10-30 19:32:55 +00:00
#region Mode Page 0x1A: Power condition page
2015-10-30 19:32:55 +00:00
/// <summary>
/// Power condition page
/// Page code 0x1A
2015-10-30 22:25:18 +00:00
/// 12 bytes in SPC-1, SPC-2, SPC-3, SPC-4
/// 40 bytes in SPC-5
2015-10-30 19:32:55 +00:00
/// </summary>
public struct ModePage_1A
{
/// <summary>
/// Parameters can be saved
/// </summary>
public bool PS;
/// <summary>
/// Idle timer activated
/// </summary>
public bool Idle;
/// <summary>
/// Standby timer activated
/// </summary>
public bool Standby;
/// <summary>
/// Idle timer
/// </summary>
public uint IdleTimer;
/// <summary>
/// Standby timer
/// </summary>
public uint StandbyTimer;
2015-10-30 22:25:18 +00:00
/// <summary>
/// Interactions between background functions and power management
/// </summary>
public byte PM_BG_Precedence;
/// <summary>
/// Standby timer Y activated
/// </summary>
public bool Standby_Y;
/// <summary>
/// Idle timer B activated
/// </summary>
public bool Idle_B;
/// <summary>
/// Idle timer C activated
/// </summary>
public bool Idle_C;
/// <summary>
/// Idle timer B
/// </summary>
public uint IdleTimer_B;
/// <summary>
/// Idle timer C
/// </summary>
public uint IdleTimer_C;
/// <summary>
/// Standby timer Y
/// </summary>
public uint StandbyTimer_Y;
public byte CCF_Idle;
public byte CCF_Standby;
public byte CCF_Stopped;
2015-10-30 19:32:55 +00:00
}
public static ModePage_1A? DecodeModePage_1A(byte[] pageResponse)
{
2016-04-19 02:11:47 +01:00
if(pageResponse == null)
2015-10-30 19:32:55 +00:00
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x40) == 0x40)
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x3F) != 0x1A)
2015-10-30 19:32:55 +00:00
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse[1] + 2 != pageResponse.Length)
2015-10-30 19:32:55 +00:00
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse.Length < 12)
2015-10-30 19:32:55 +00:00
return null;
ModePage_1A decoded = new ModePage_1A();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.Standby |= (pageResponse[3] & 0x01) == 0x01;
decoded.Idle |= (pageResponse[3] & 0x02) == 0x02;
decoded.IdleTimer = (uint)((pageResponse[4] << 24) + (pageResponse[5] << 16) + (pageResponse[6] << 8) + pageResponse[7]);
decoded.StandbyTimer = (uint)((pageResponse[8] << 24) + (pageResponse[9] << 16) + (pageResponse[10] << 8) + pageResponse[11]);
2016-04-19 02:11:47 +01:00
if(pageResponse.Length < 40)
2015-10-30 22:25:18 +00:00
return decoded;
decoded.PM_BG_Precedence = (byte)((pageResponse[2] & 0xC0) >> 6);
decoded.Standby_Y |= (pageResponse[2] & 0x01) == 0x01;
decoded.Idle_B |= (pageResponse[3] & 0x04) == 0x04;
decoded.Idle_C |= (pageResponse[3] & 0x08) == 0x08;
decoded.IdleTimer_B = (uint)((pageResponse[12] << 24) + (pageResponse[13] << 16) + (pageResponse[14] << 8) + pageResponse[15]);
decoded.IdleTimer_C = (uint)((pageResponse[16] << 24) + (pageResponse[17] << 16) + (pageResponse[18] << 8) + pageResponse[19]);
decoded.StandbyTimer_Y = (uint)((pageResponse[20] << 24) + (pageResponse[21] << 16) + (pageResponse[22] << 8) + pageResponse[23]);
decoded.CCF_Idle = (byte)((pageResponse[39] & 0xC0) >> 6);
decoded.CCF_Standby = (byte)((pageResponse[39] & 0x30) >> 4);
decoded.CCF_Stopped = (byte)((pageResponse[39] & 0x0C) >> 2);
2015-10-30 19:32:55 +00:00
return decoded;
}
public static string PrettifyModePage_1A(byte[] pageResponse)
{
return PrettifyModePage_1A(DecodeModePage_1A(pageResponse));
}
public static string PrettifyModePage_1A(ModePage_1A? modePage)
{
2016-04-19 02:11:47 +01:00
if(!modePage.HasValue)
2015-10-30 19:32:55 +00:00
return null;
ModePage_1A page = modePage.Value;
StringBuilder sb = new StringBuilder();
sb.AppendLine("SCSI Power condition page:");
2016-04-19 02:11:47 +01:00
if(page.PS)
2015-10-30 19:32:55 +00:00
sb.AppendLine("\tParameters can be saved");
2016-04-19 02:11:47 +01:00
if((page.Standby && page.StandbyTimer > 0) ||
(page.Standby_Y && page.StandbyTimer_Y > 0))
2015-10-30 22:25:18 +00:00
{
2016-04-19 02:11:47 +01:00
if(page.Standby && page.StandbyTimer > 0)
2015-10-30 22:25:18 +00:00
sb.AppendFormat("\tStandby timer Z is set to {0} ms", page.StandbyTimer * 100).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.Standby_Y && page.StandbyTimer_Y > 0)
2015-10-30 22:25:18 +00:00
sb.AppendFormat("\tStandby timer Y is set to {0} ms", page.StandbyTimer_Y * 100).AppendLine();
}
2015-10-30 19:32:55 +00:00
else
sb.AppendLine("\tDrive will not enter standy mode");
2016-04-19 02:11:47 +01:00
if((page.Idle && page.IdleTimer > 0) ||
2015-10-30 22:25:18 +00:00
(page.Idle_B && page.IdleTimer_B > 0) ||
(page.Idle_C && page.IdleTimer_C > 0))
{
2016-04-19 02:11:47 +01:00
if(page.Idle && page.IdleTimer > 0)
2015-10-30 22:25:18 +00:00
sb.AppendFormat("\tIdle timer A is set to {0} ms", page.IdleTimer * 100).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.Idle_B && page.IdleTimer_B > 0)
2015-10-30 22:25:18 +00:00
sb.AppendFormat("\tIdle timer B is set to {0} ms", page.IdleTimer_B * 100).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.Idle_C && page.IdleTimer_C > 0)
2015-10-30 22:25:18 +00:00
sb.AppendFormat("\tIdle timer C is set to {0} ms", page.IdleTimer_C * 100).AppendLine();
}
2015-10-30 19:32:55 +00:00
else
sb.AppendLine("\tDrive will not enter idle mode");
2016-04-19 02:11:47 +01:00
switch(page.PM_BG_Precedence)
2015-10-30 22:25:18 +00:00
{
case 0:
break;
case 1:
sb.AppendLine("\tPerforming background functions take precedence over maintaining low power conditions");
break;
case 2:
sb.AppendLine("\tMaintaining low power conditions take precedence over performing background functions");
break;
}
2015-10-30 19:32:55 +00:00
return sb.ToString();
}
2015-10-30 19:32:55 +00:00
#endregion Mode Page 0x1A: Power condition page
#region Mode Page 0x0A subpage 0x01: Control Extension mode page
/// <summary>
/// Control Extension mode page
/// Page code 0x0A
/// Subpage code 0x01
2015-10-30 22:25:18 +00:00
/// 32 bytes in SPC-3, SPC-4, SPC-5
/// </summary>
public struct ModePage_0A_S01
{
/// <summary>
/// Parameters can be saved
/// </summary>
public bool PS;
/// <summary>
/// Timestamp outside this standard
/// </summary>
public bool TCMOS;
/// <summary>
/// SCSI precedence
/// </summary>
public bool SCSIP;
/// <summary>
/// Implicit Asymmetric Logical Unit Access Enabled
/// </summary>
public bool IALUAE;
/// <summary>
/// Initial task priority
/// </summary>
public byte InitialPriority;
2015-10-30 22:25:18 +00:00
/// <summary>
/// Device life control disabled
/// </summary>
public bool DLC;
/// <summary>
/// Maximum size of SENSE data in bytes
/// </summary>
public byte MaximumSenseLength;
}
public static ModePage_0A_S01? DecodeModePage_0A_S01(byte[] pageResponse)
{
2016-04-19 02:11:47 +01:00
if(pageResponse == null)
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x40) != 0x40)
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x3F) != 0x0A)
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse[1] != 0x01)
return null;
2016-04-19 02:11:47 +01:00
if(((pageResponse[2] << 8) + pageResponse[3] + 4) != pageResponse.Length)
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse.Length < 32)
return null;
ModePage_0A_S01 decoded = new ModePage_0A_S01();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.IALUAE |= (pageResponse[4] & 0x01) == 0x01;
decoded.SCSIP |= (pageResponse[4] & 0x02) == 0x02;
decoded.TCMOS |= (pageResponse[4] & 0x04) == 0x04;
decoded.InitialPriority = (byte)(pageResponse[5] & 0x0F);
return decoded;
}
public static string PrettifyModePage_0A_S01(byte[] pageResponse)
{
return PrettifyModePage_0A_S01(DecodeModePage_0A_S01(pageResponse));
}
public static string PrettifyModePage_0A_S01(ModePage_0A_S01? modePage)
{
2016-04-19 02:11:47 +01:00
if(!modePage.HasValue)
return null;
ModePage_0A_S01 page = modePage.Value;
StringBuilder sb = new StringBuilder();
sb.AppendLine("SCSI Control extension page:");
2016-04-19 02:11:47 +01:00
if(page.PS)
sb.AppendLine("\tParameters can be saved");
2016-04-19 02:11:47 +01:00
if(page.TCMOS)
{
sb.Append("\tTimestamp can be initialized by methods outside of the SCSI standards");
2016-04-19 02:11:47 +01:00
if(page.SCSIP)
sb.Append(", but SCSI's SET TIMESTAMP shall take precedence over them");
sb.AppendLine();
}
2016-04-19 02:11:47 +01:00
if(page.IALUAE)
sb.AppendLine("\tImplicit Asymmetric Logical Unit Access is enabled");
2015-10-30 22:25:18 +00:00
sb.AppendFormat("\tInitial priority is {0}", page.InitialPriority).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.DLC)
2015-10-30 22:25:18 +00:00
sb.AppendLine("\tDevice will not degrade performance to extend its life");
2016-04-19 02:11:47 +01:00
if(page.MaximumSenseLength > 0)
2015-10-30 22:25:18 +00:00
sb.AppendFormat("\tMaximum sense data would be {0} bytes", page.MaximumSenseLength).AppendLine();
return sb.ToString();
}
#endregion Mode Page 0x0A subpage 0x01: Control Extension mode page
#region Mode Page 0x1A subpage 0x01: Power Consumption mode page
/// <summary>
/// Power Consumption mode page
/// Page code 0x1A
/// Subpage code 0x01
/// 16 bytes in SPC-5
/// </summary>
public struct ModePage_1A_S01
{
/// <summary>
/// Parameters can be saved
/// </summary>
public bool PS;
/// <summary>
/// Active power level
/// </summary>
public byte ActiveLevel;
/// <summary>
/// Power Consumption VPD identifier in use
/// </summary>
public byte PowerConsumptionIdentifier;
}
public static ModePage_1A_S01? DecodeModePage_1A_S01(byte[] pageResponse)
{
2016-04-19 02:11:47 +01:00
if(pageResponse == null)
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x40) != 0x40)
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x3F) != 0x1A)
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse[1] != 0x01)
return null;
2016-04-19 02:11:47 +01:00
if(((pageResponse[2] << 8) + pageResponse[3] + 4) != pageResponse.Length)
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse.Length < 16)
return null;
ModePage_1A_S01 decoded = new ModePage_1A_S01();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.ActiveLevel = (byte)(pageResponse[6] & 0x03);
decoded.PowerConsumptionIdentifier = pageResponse[7];
return decoded;
}
public static string PrettifyModePage_1A_S01(byte[] pageResponse)
{
return PrettifyModePage_1A_S01(DecodeModePage_1A_S01(pageResponse));
}
public static string PrettifyModePage_1A_S01(ModePage_1A_S01? modePage)
{
2016-04-19 02:11:47 +01:00
if(!modePage.HasValue)
return null;
ModePage_1A_S01 page = modePage.Value;
StringBuilder sb = new StringBuilder();
sb.AppendLine("SCSI Power Consumption page:");
2016-04-19 02:11:47 +01:00
if(page.PS)
sb.AppendLine("\tParameters can be saved");
2016-04-19 02:11:47 +01:00
switch(page.ActiveLevel)
{
case 0:
sb.AppendFormat("\tDevice power consumption is dictated by identifier {0} of Power Consumption VPD", page.PowerConsumptionIdentifier).AppendLine();
break;
case 1:
sb.AppendLine("\tDevice is in highest relative power consumption level");
break;
case 2:
sb.AppendLine("\tDevice is in intermediate relative power consumption level");
break;
case 3:
sb.AppendLine("\tDevice is in lowest relative power consumption level");
break;
}
return sb.ToString();
}
#endregion Mode Page 0x1A subpage 0x01: Power Consumption mode page
#region Mode Page 0x10: XOR control mode page
/// <summary>
/// XOR control mode page
/// Page code 0x10
2015-10-31 01:31:51 +00:00
/// 24 bytes in SBC-1, SBC-2
/// </summary>
public struct ModePage_10
{
/// <summary>
/// Parameters can be saved
/// </summary>
public bool PS;
/// <summary>
/// Disables XOR operations
/// </summary>
public bool XORDIS;
/// <summary>
/// Maximum transfer length in blocks for a XOR command
/// </summary>
public uint MaxXorWrite;
/// <summary>
/// Maximum regenerate length in blocks
/// </summary>
public uint MaxRegenSize;
/// <summary>
/// Maximum transfer length in blocks for READ during a rebuild
/// </summary>
public uint MaxRebuildRead;
/// <summary>
/// Minimum time in ms between READs during a rebuild
/// </summary>
public ushort RebuildDelay;
}
public static ModePage_10? DecodeModePage_10(byte[] pageResponse)
{
2016-04-19 02:11:47 +01:00
if(pageResponse == null)
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x40) == 0x40)
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x3F) != 0x10)
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse.Length < 24)
return null;
ModePage_10 decoded = new ModePage_10();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.XORDIS |= (pageResponse[2] & 0x02) == 0x02;
decoded.MaxXorWrite = (uint)((pageResponse[4] << 24) + (pageResponse[5] << 16) + (pageResponse[6] << 8) + pageResponse[7]);
decoded.MaxRegenSize = (uint)((pageResponse[12] << 24) + (pageResponse[13] << 16) + (pageResponse[14] << 8) + pageResponse[15]);
decoded.MaxRebuildRead = (uint)((pageResponse[16] << 24) + (pageResponse[17] << 16) + (pageResponse[18] << 8) + pageResponse[19]);
decoded.RebuildDelay = (ushort)((pageResponse[22] << 8) + pageResponse[23]);
return decoded;
}
public static string PrettifyModePage_10(byte[] pageResponse)
{
return PrettifyModePage_10(DecodeModePage_10(pageResponse));
}
public static string PrettifyModePage_10(ModePage_10? modePage)
{
2016-04-19 02:11:47 +01:00
if(!modePage.HasValue)
return null;
ModePage_10 page = modePage.Value;
StringBuilder sb = new StringBuilder();
sb.AppendLine("SCSI XOR control mode page:");
2016-04-19 02:11:47 +01:00
if(page.PS)
sb.AppendLine("\tParameters can be saved");
2016-04-19 02:11:47 +01:00
if(page.XORDIS)
sb.AppendLine("\tXOR operations are disabled");
else
{
2016-04-19 02:11:47 +01:00
if(page.MaxXorWrite > 0)
sb.AppendFormat("\tDrive accepts a maximum of {0} blocks in a single XOR WRITE command", page.MaxXorWrite).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.MaxRegenSize > 0)
sb.AppendFormat("\tDrive accepts a maximum of {0} blocks in a REGENERATE command", page.MaxRegenSize).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.MaxRebuildRead > 0)
sb.AppendFormat("\tDrive accepts a maximum of {0} blocks in a READ command during rebuild", page.MaxRebuildRead).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.RebuildDelay > 0)
sb.AppendFormat("\tDrive needs a minimum of {0} ms between READ commands during rebuild", page.RebuildDelay).AppendLine();
}
return sb.ToString();
}
#endregion Mode Page 0x10: XOR control mode page
#region Mode Page 0x1C subpage 0x01: Background Control mode page
/// <summary>
/// Background Control mode page
/// Page code 0x1A
/// Subpage code 0x01
/// 16 bytes in SPC-5
/// </summary>
public struct ModePage_1C_S01
{
/// <summary>
/// Parameters can be saved
/// </summary>
public bool PS;
/// <summary>
/// Suspend on log full
/// </summary>
public bool S_L_Full;
/// <summary>
/// Log only when intervention required
/// </summary>
public bool LOWIR;
/// <summary>
/// Enable background medium scan
/// </summary>
public bool En_Bms;
/// <summary>
/// Enable background pre-scan
/// </summary>
public bool En_Ps;
/// <summary>
/// Time in hours between background medium scans
/// </summary>
public ushort BackgroundScanInterval;
/// <summary>
/// Maximum time in hours for a background pre-scan to complete
/// </summary>
public ushort BackgroundPrescanTimeLimit;
/// <summary>
/// Minimum time in ms being idle before resuming a background scan
/// </summary>
public ushort MinIdleBeforeBgScan;
/// <summary>
/// Maximum time in ms to start processing commands while performing a background scan
/// </summary>
public ushort MaxTimeSuspendBgScan;
}
public static ModePage_1C_S01? DecodeModePage_1C_S01(byte[] pageResponse)
{
2016-04-19 02:11:47 +01:00
if(pageResponse == null)
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x40) != 0x40)
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x3F) != 0x1C)
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse[1] != 0x01)
return null;
2016-04-19 02:11:47 +01:00
if(((pageResponse[2] << 8) + pageResponse[3] + 4) != pageResponse.Length)
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse.Length < 16)
return null;
ModePage_1C_S01 decoded = new ModePage_1C_S01();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.S_L_Full |= (pageResponse[4] & 0x04) == 0x04;
decoded.LOWIR |= (pageResponse[4] & 0x02) == 0x02;
decoded.En_Bms |= (pageResponse[4] & 0x01) == 0x01;
decoded.En_Ps |= (pageResponse[5] & 0x01) == 0x01;
decoded.BackgroundScanInterval = (ushort)((pageResponse[6] << 8) + pageResponse[7]);
decoded.BackgroundPrescanTimeLimit = (ushort)((pageResponse[8] << 8) + pageResponse[9]);
decoded.MinIdleBeforeBgScan = (ushort)((pageResponse[10] << 8) + pageResponse[11]);
decoded.MaxTimeSuspendBgScan = (ushort)((pageResponse[12] << 8) + pageResponse[13]);
return decoded;
}
public static string PrettifyModePage_1C_S01(byte[] pageResponse)
{
return PrettifyModePage_1C_S01(DecodeModePage_1C_S01(pageResponse));
}
public static string PrettifyModePage_1C_S01(ModePage_1C_S01? modePage)
{
2016-04-19 02:11:47 +01:00
if(!modePage.HasValue)
return null;
ModePage_1C_S01 page = modePage.Value;
StringBuilder sb = new StringBuilder();
sb.AppendLine("SCSI Background Control page:");
2016-04-19 02:11:47 +01:00
if(page.PS)
sb.AppendLine("\tParameters can be saved");
2016-04-19 02:11:47 +01:00
if(page.S_L_Full)
sb.AppendLine("\tBackground scans will be halted if log is full");
2016-04-19 02:11:47 +01:00
if(page.LOWIR)
sb.AppendLine("\tBackground scans will only be logged if they require intervention");
2016-04-19 02:11:47 +01:00
if(page.En_Bms)
sb.AppendLine("\tBackground medium scans are enabled");
2016-04-19 02:11:47 +01:00
if(page.En_Ps)
sb.AppendLine("\tBackground pre-scans are enabled");
2016-04-19 02:11:47 +01:00
if(page.BackgroundScanInterval > 0)
sb.AppendFormat("\t{0} hours shall be between the start of a background scan operation and the next", page.BackgroundScanInterval).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.BackgroundPrescanTimeLimit > 0)
sb.AppendFormat("\tBackgroun pre-scan operations can take a maximum of {0} hours", page.BackgroundPrescanTimeLimit).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.MinIdleBeforeBgScan > 0)
sb.AppendFormat("\tAt least {0} ms must be idle before resuming a suspended background scan operation", page.MinIdleBeforeBgScan).AppendLine();
2016-04-19 02:11:47 +01:00
if(page.MaxTimeSuspendBgScan > 0)
sb.AppendFormat("\tAt most {0} ms must be before suspending a background scan operation and processing received commands", page.MaxTimeSuspendBgScan).AppendLine();
return sb.ToString();
}
#endregion Mode Page 0x1C subpage 0x01: Background Control mode page
#region Mode Page 0x0F: Data compression page
/// <summary>
/// Data compression page
/// Page code 0x0F
/// 16 bytes in SSC-1, SSC-2, SSC-3
/// </summary>
public struct ModePage_0F
{
/// <summary>
/// Parameters can be saved
/// </summary>
public bool PS;
/// <summary>
/// Data compression enabled
/// </summary>
public bool DCE;
/// <summary>
/// Data compression capable
/// </summary>
public bool DCC;
/// <summary>
/// Data decompression enabled
/// </summary>
public bool DDE;
/// <summary>
/// Report exception on decompression
/// </summary>
public byte RED;
/// <summary>
/// Compression algorithm
/// </summary>
public uint CompressionAlgo;
/// <summary>
/// Decompression algorithm
/// </summary>
public uint DecompressionAlgo;
}
public static ModePage_0F? DecodeModePage_0F(byte[] pageResponse)
{
2016-04-19 02:11:47 +01:00
if(pageResponse == null)
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x40) == 0x40)
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x3F) != 0x0F)
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse.Length < 16)
return null;
ModePage_0F decoded = new ModePage_0F();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.DCE |= (pageResponse[2] & 0x80) == 0x80;
decoded.DCC |= (pageResponse[2] & 0x40) == 0x40;
decoded.DDE |= (pageResponse[3] & 0x80) == 0x80;
decoded.RED = (byte)((pageResponse[3] & 0x60) >> 5);
decoded.CompressionAlgo = (uint)((pageResponse[4] << 24) + (pageResponse[5] << 16) + (pageResponse[6] << 8) + pageResponse[7]);
decoded.DecompressionAlgo = (uint)((pageResponse[8] << 24) + (pageResponse[9] << 16) + (pageResponse[10] << 8) + pageResponse[11]);
return decoded;
}
public static string PrettifyModePage_0F(byte[] pageResponse)
{
return PrettifyModePage_0F(DecodeModePage_0F(pageResponse));
}
public static string PrettifyModePage_0F(ModePage_0F? modePage)
{
2016-04-19 02:11:47 +01:00
if(!modePage.HasValue)
return null;
ModePage_0F page = modePage.Value;
StringBuilder sb = new StringBuilder();
sb.AppendLine("SCSI Data compression page:");
2016-04-19 02:11:47 +01:00
if(page.PS)
sb.AppendLine("\tParameters can be saved");
2016-04-19 02:11:47 +01:00
if(page.DCC)
{
sb.AppendLine("\tDrive supports data compression");
2016-04-19 02:11:47 +01:00
if(page.DCE)
{
sb.Append("\tData compression is enabled with ");
2016-04-19 02:11:47 +01:00
switch(page.CompressionAlgo)
{
case 3:
sb.AppendLine("IBM ALDC with 512 byte buffer");
break;
case 4:
sb.AppendLine("IBM ALDC with 1024 byte buffer");
break;
case 5:
sb.AppendLine("IBM ALDC with 2048 byte buffer");
break;
case 0x10:
sb.AppendLine("IBM IDRC");
break;
case 0x20:
sb.AppendLine("DCLZ");
break;
case 0xFF:
sb.AppendLine("an unregistered compression algorithm");
break;
default:
sb.AppendFormat("an unknown algorithm coded {0}", page.CompressionAlgo).AppendLine();
break;
}
}
2016-04-19 02:11:47 +01:00
if(page.DDE)
{
sb.AppendLine("\tData decompression is enabled");
2016-04-19 02:11:47 +01:00
if(page.DecompressionAlgo == 0)
sb.AppendLine("\tLast data read was uncompressed");
else
{
sb.Append("\tLast data read was compressed with ");
2016-04-19 02:11:47 +01:00
switch(page.CompressionAlgo)
{
case 3:
sb.AppendLine("IBM ALDC with 512 byte buffer");
break;
case 4:
sb.AppendLine("IBM ALDC with 1024 byte buffer");
break;
case 5:
sb.AppendLine("IBM ALDC with 2048 byte buffer");
break;
case 0x10:
sb.AppendLine("IBM IDRC");
break;
case 0x20:
sb.AppendLine("DCLZ");
break;
case 0xFF:
sb.AppendLine("an unregistered compression algorithm");
break;
default:
sb.AppendFormat("an unknown algorithm coded {0}", page.CompressionAlgo).AppendLine();
break;
}
}
}
sb.AppendFormat("\tReport exception on compression is set to {0}", page.RED).AppendLine();
}
else
sb.AppendLine("\tDrive does not support data compression");
return sb.ToString();
}
#endregion Mode Page 0x0F: Data compression page
#region Mode Page 0x1B: Removable Block Access Capabilities page
/// <summary>
/// Removable Block Access Capabilities page
/// Page code 0x1B
/// 12 bytes in INF-8070
/// </summary>
public struct ModePage_1B
{
/// <summary>
/// Parameters can be saved
/// </summary>
public bool PS;
/// <summary>
/// Supports reporting progress of format
/// </summary>
public bool SRFP;
/// <summary>
/// Non-CD Optical Device
/// </summary>
public bool NCD;
/// <summary>
/// Phase change dual device supporting a CD and a Non-CD Optical devices
/// </summary>
public bool SML;
/// <summary>
/// Total number of LUNs
/// </summary>
public byte TLUN;
/// <summary>
/// System Floppy Type device
/// </summary>
public bool SFLP;
}
public static ModePage_1B? DecodeModePage_1B(byte[] pageResponse)
{
2016-04-19 02:11:47 +01:00
if(pageResponse == null)
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x40) == 0x40)
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x3F) != 0x1B)
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse.Length < 12)
return null;
ModePage_1B decoded = new ModePage_1B();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.SFLP |= (pageResponse[2] & 0x80) == 0x80;
decoded.SRFP |= (pageResponse[2] & 0x40) == 0x40;
decoded.NCD |= (pageResponse[3] & 0x80) == 0x80;
decoded.SML |= (pageResponse[3] & 0x40) == 0x40;
decoded.TLUN = (byte)(pageResponse[3] & 0x07);
return decoded;
}
public static string PrettifyModePage_1B(byte[] pageResponse)
{
return PrettifyModePage_1B(DecodeModePage_1B(pageResponse));
}
public static string PrettifyModePage_1B(ModePage_1B? modePage)
{
2016-04-19 02:11:47 +01:00
if(!modePage.HasValue)
return null;
ModePage_1B page = modePage.Value;
StringBuilder sb = new StringBuilder();
sb.AppendLine("SCSI Removable Block Access Capabilities page:");
2016-04-19 02:11:47 +01:00
if(page.PS)
sb.AppendLine("\tParameters can be saved");
2016-04-19 02:11:47 +01:00
if(page.SFLP)
sb.AppendLine("\tDrive can be used as a system floppy device");
2016-04-19 02:11:47 +01:00
if(page.SRFP)
sb.AppendLine("\tDrive supports reporting progress of format");
2016-04-19 02:11:47 +01:00
if(page.NCD)
sb.AppendLine("\tDrive is a Non-CD Optical Device");
2016-04-19 02:11:47 +01:00
if(page.SML)
sb.AppendLine("\tDevice is a dual device supporting CD and Non-CD Optical");
2016-04-19 02:11:47 +01:00
if(page.TLUN > 0)
sb.AppendFormat("\tDrive supports {0} LUNs", page.TLUN).AppendLine();
return sb.ToString();
}
#endregion Mode Page 0x1B: Removable Block Access Capabilities page
#region Mode Page 0x1C: Timer & Protect page
/// <summary>
/// Timer & Protect page
/// Page code 0x1C
/// 8 bytes in INF-8070
/// </summary>
public struct ModePage_1C_SFF
{
/// <summary>
/// Parameters can be saved
/// </summary>
public bool PS;
/// <summary>
/// Time the device shall remain in the current state after seek, read or write operation
/// </summary>
public byte InactivityTimeMultiplier;
/// <summary>
/// Disabled until power cycle
/// </summary>
public bool DISP;
/// <summary>
/// Software Write Protect until Power-down
/// </summary>
public bool SWPP;
}
public static ModePage_1C_SFF? DecodeModePage_1C_SFF(byte[] pageResponse)
{
2016-04-19 02:11:47 +01:00
if(pageResponse == null)
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x40) == 0x40)
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x3F) != 0x1C)
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse.Length < 8)
return null;
ModePage_1C_SFF decoded = new ModePage_1C_SFF();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.DISP |= (pageResponse[2] & 0x02) == 0x02;
decoded.SWPP |= (pageResponse[3] & 0x01) == 0x01;
decoded.InactivityTimeMultiplier = (byte)(pageResponse[3] & 0x0F);
return decoded;
}
public static string PrettifyModePage_1C_SFF(byte[] pageResponse)
{
return PrettifyModePage_1C_SFF(DecodeModePage_1C_SFF(pageResponse));
}
public static string PrettifyModePage_1C_SFF(ModePage_1C_SFF? modePage)
{
2016-04-19 02:11:47 +01:00
if(!modePage.HasValue)
return null;
ModePage_1C_SFF page = modePage.Value;
StringBuilder sb = new StringBuilder();
sb.AppendLine("SCSI Timer & Protect page:");
2016-04-19 02:11:47 +01:00
if(page.PS)
sb.AppendLine("\tParameters can be saved");
2016-04-19 02:11:47 +01:00
if(page.DISP)
sb.AppendLine("\tDrive is disabled until power is cycled");
2016-04-19 02:11:47 +01:00
if(page.SWPP)
sb.AppendLine("\tDrive is software write-protected until powered down");
2016-04-19 02:11:47 +01:00
switch(page.InactivityTimeMultiplier)
{
case 0:
sb.AppendLine("\tDrive will remain in same status a vendor-specified time after a seek, read or write operation");
break;
case 1:
sb.AppendLine("\tDrive will remain in same status 125 ms after a seek, read or write operation");
break;
case 2:
sb.AppendLine("\tDrive will remain in same status 250 ms after a seek, read or write operation");
break;
case 3:
sb.AppendLine("\tDrive will remain in same status 500 ms after a seek, read or write operation");
break;
case 4:
sb.AppendLine("\tDrive will remain in same status 1 second after a seek, read or write operation");
break;
case 5:
sb.AppendLine("\tDrive will remain in same status 2 seconds after a seek, read or write operation");
break;
case 6:
sb.AppendLine("\tDrive will remain in same status 4 seconds after a seek, read or write operation");
break;
case 7:
sb.AppendLine("\tDrive will remain in same status 8 seconds after a seek, read or write operation");
break;
case 8:
sb.AppendLine("\tDrive will remain in same status 16 seconds after a seek, read or write operation");
break;
case 9:
sb.AppendLine("\tDrive will remain in same status 32 seconds after a seek, read or write operation");
break;
case 10:
sb.AppendLine("\tDrive will remain in same status 1 minute after a seek, read or write operation");
break;
case 11:
sb.AppendLine("\tDrive will remain in same status 2 minutes after a seek, read or write operation");
break;
case 12:
sb.AppendLine("\tDrive will remain in same status 4 minutes after a seek, read or write operation");
break;
case 13:
sb.AppendLine("\tDrive will remain in same status 8 minutes after a seek, read or write operation");
break;
case 14:
sb.AppendLine("\tDrive will remain in same status 16 minutes after a seek, read or write operation");
break;
case 15:
sb.AppendLine("\tDrive will remain in same status 32 minutes after a seek, read or write operation");
break;
}
return sb.ToString();
}
#endregion Mode Page 0x1C: Timer & Protect page
#region Mode Page 0x00: Drive Operation Mode page
/// <summary>
/// Drive Operation Mode page
/// Page code 0x00
/// 4 bytes in INF-8070
/// </summary>
public struct ModePage_00_SFF
{
/// <summary>
/// Parameters can be saved
/// </summary>
public bool PS;
/// <summary>
/// Select LUN Mode
/// </summary>
public bool SLM;
/// <summary>
/// Select LUN for rewritable
/// </summary>
public bool SLR;
/// <summary>
/// Disable verify for WRITE
/// </summary>
public bool DVW;
/// <summary>
/// Disable deferred error
/// </summary>
public bool DDE;
}
public static ModePage_00_SFF? DecodeModePage_00_SFF(byte[] pageResponse)
{
2016-04-19 02:11:47 +01:00
if(pageResponse == null)
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x40) == 0x40)
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x3F) != 0x00)
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse.Length < 4)
return null;
ModePage_00_SFF decoded = new ModePage_00_SFF();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.SLM |= (pageResponse[2] & 0x80) == 0x80;
decoded.SLR |= (pageResponse[2] & 0x40) == 0x40;
decoded.DVW |= (pageResponse[2] & 0x20) == 0x20;
decoded.DDE |= (pageResponse[3] & 0x10) == 0x10;
return decoded;
}
public static string PrettifyModePage_00_SFF(byte[] pageResponse)
{
return PrettifyModePage_00_SFF(DecodeModePage_00_SFF(pageResponse));
}
public static string PrettifyModePage_00_SFF(ModePage_00_SFF? modePage)
{
2016-04-19 02:11:47 +01:00
if(!modePage.HasValue)
return null;
ModePage_00_SFF page = modePage.Value;
StringBuilder sb = new StringBuilder();
sb.AppendLine("SCSI Drive Operation Mode page:");
2016-04-19 02:11:47 +01:00
if(page.PS)
sb.AppendLine("\tParameters can be saved");
2016-04-19 02:11:47 +01:00
if(page.DVW)
sb.AppendLine("\tVerifying after writing is disabled");
2016-04-19 02:11:47 +01:00
if(page.DDE)
sb.AppendLine("\tDrive will abort when a writing error is detected");
2016-04-19 02:11:47 +01:00
if(page.SLM)
{
sb.Append("\tDrive has two LUNs with rewritable being ");
2016-04-19 02:11:47 +01:00
if(page.SLM)
sb.AppendLine("LUN 1");
else
sb.AppendLine("LUN 0");
}
return sb.ToString();
}
#endregion Mode Page 0x00: Drive Operation Mode page
2015-10-31 19:41:58 +00:00
public struct ModePage
2015-10-31 19:41:58 +00:00
{
public byte Page;
public byte Subpage;
public byte[] PageResponse;
}
public struct DecodedMode
{
public ModeHeader Header;
public ModePage[] Pages;
2015-10-31 19:41:58 +00:00
}
public static DecodedMode? DecodeMode6(byte[] modeResponse, PeripheralDeviceTypes deviceType)
{
ModeHeader? hdr = DecodeModeHeader6(modeResponse, deviceType);
2016-04-19 02:11:47 +01:00
if(!hdr.HasValue)
2015-10-31 19:41:58 +00:00
return null;
DecodedMode decoded = new DecodedMode();
decoded.Header = hdr.Value;
int blkDrLength = 0;
2016-04-19 02:11:47 +01:00
if(decoded.Header.BlockDescriptors != null)
blkDrLength = decoded.Header.BlockDescriptors.Length;
2015-10-31 19:41:58 +00:00
int offset = 4 + blkDrLength * 8;
int length = modeResponse[0] + 1;
2015-10-31 19:41:58 +00:00
2016-04-19 02:11:47 +01:00
if(length != modeResponse.Length)
2015-10-31 19:41:58 +00:00
return decoded;
List<ModePage> listpages = new List<ModePage>();
2015-10-31 19:41:58 +00:00
2016-04-19 02:11:47 +01:00
while(offset < modeResponse.Length)
2015-10-31 19:41:58 +00:00
{
bool isSubpage = (modeResponse[offset] & 0x40) == 0x40;
ModePage pg = new ModePage();
* commandline: * DiscImageChef.Settings/Settings.cs: * DiscImageChef.Settings/docs/README.txt: * DiscImageChef.Settings/packages.config: * DiscImageChef.Settings/docs/LICENSE.txt: * DiscImageChef.Settings/docs/ChangeLog.txt: * DiscImageChef.Settings/docs/mono/index.xml: * DiscImageChef.Settings/docs/html/index.html: * DiscImageChef.Settings/Properties/AssemblyInfo.cs: * DiscImageChef.Settings/DiscImageChef.Settings.csproj: * DiscImageChef.Settings/docs/mono/ns-Claunia.PropertyList.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/UID.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/UID.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSSet.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/index.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSSet.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSDate.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSData.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSDate.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSData.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSArray.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSNumber.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSString.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSObject.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSArray.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSNumber.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSString.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSObject.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSDictionary.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSDictionary.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/PropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/PropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/XmlPropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/XmlPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/ASCIIPropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/ASCIIPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/BinaryPropertyListParser.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/BinaryPropertyListWriter.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/BinaryPropertyListWriter.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/BinaryPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/PropertyListFormatException.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/PropertyListFormatException.html: Added supports for settings * DiscImageChef/Commands/Configure.cs: Added support for settings. * DiscImageChef/Core/Statistics.cs: * DiscImageChef/Commands/Verify.cs: * DiscImageChef/Commands/Entropy.cs: * DiscImageChef/Commands/Formats.cs: * DiscImageChef/Commands/PrintHex.cs: * DiscImageChef/Commands/MediaInfo.cs: * DiscImageChef/Commands/Statistics.cs: Added statistics. * DiscImageChef.Decoders/SCSI/Inquiry.cs: Corrected bug on inquiry decoding. * DiscImageChef.Decoders/SCSI/Modes.cs: Corrected bug on decoding mode page 2Ah without write performance descriptors. Corrected bug when there is a vendor page 0 in mode sense decoding. * DiscImageChef.Devices/Device/Constructor.cs: Corrected detecting USB or FireWire attached CD/DVD/BD and tape drives. Try ATA identify on USB or FireWire that don't have SCSI INQUIRY. * DiscImageChef.DiscImages/CDRWin.cs: Corrected CD-ROM XA vs CD-ROM detection. * DiscImageChef.Partitions/AppleMap.cs: Corrected big endian working. Added debug output. * DiscImageChef.sln: Added supports for settings. * DiscImageChef/Commands/Decode.cs: * DiscImageChef/Commands/Analyze.cs: * DiscImageChef/Commands/Compare.cs: * DiscImageChef/Commands/Checksum.cs: * DiscImageChef/Commands/Benchmark.cs: * DiscImageChef/Commands/DeviceInfo.cs: * DiscImageChef/Commands/CreateSidecar.cs: Added statistics. * DiscImageChef/Commands/DeviceReport.cs: Added statistics. Correct handling empty inquiry string fields. Suppose it is not removable, til proved wrong. Corrected MODE SENSE (6/10) detection and calling order. If device is MMC type but reports neither mode page 2Ah neither GET CONFIGURATION, try all CDs (old drives work like that). Try reading Lead-In and Lead-Out in Audio CD using Audio READ CD commands. Corrected READ LONG information handling, some drives return 2s-complement in 32 bit. Upper 16 bits are ignored. Added support for DVD raw block (37856 bytes). Check READ LONG up to 36 times the cooked block size. That should be enough to detect huge blocked media (like DVD and BD) without taking ages. If READ LONG size had to be bruteforced, and debug is activated, save the result. * DiscImageChef/Commands/DumpMedia.cs: Added statistics. Corrected READ LONG information handling, some drives return 2s-complement in 32 bit. Upper 16 bits are ignored. Start trying with 64 blocks at a time. Some drives report to be able to read 255 at a time, but they really don't, they take a lot longer to read. * DiscImageChef/Commands/MediaScan.cs: Added statistics. Start trying with 64 blocks at a time. Some drives report to be able to read 255 at a time, but they really don't, they take a lot longer to read. * DiscImageChef/DiscImageChef.csproj: Added support for settings. Added statistics. * DiscImageChef/Main.cs: * DiscImageChef/Options.cs: Added support for settings. Added statistics.
2016-02-03 18:58:11 +00:00
byte pageNo = (byte)(modeResponse[offset] & 0x3F);
2015-10-31 19:41:58 +00:00
2016-04-19 02:11:47 +01:00
if(pageNo == 0)
{
* commandline: * DiscImageChef.Settings/Settings.cs: * DiscImageChef.Settings/docs/README.txt: * DiscImageChef.Settings/packages.config: * DiscImageChef.Settings/docs/LICENSE.txt: * DiscImageChef.Settings/docs/ChangeLog.txt: * DiscImageChef.Settings/docs/mono/index.xml: * DiscImageChef.Settings/docs/html/index.html: * DiscImageChef.Settings/Properties/AssemblyInfo.cs: * DiscImageChef.Settings/DiscImageChef.Settings.csproj: * DiscImageChef.Settings/docs/mono/ns-Claunia.PropertyList.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/UID.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/UID.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSSet.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/index.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSSet.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSDate.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSData.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSDate.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSData.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSArray.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSNumber.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSString.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSObject.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSArray.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSNumber.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSString.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSObject.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSDictionary.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSDictionary.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/PropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/PropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/XmlPropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/XmlPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/ASCIIPropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/ASCIIPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/BinaryPropertyListParser.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/BinaryPropertyListWriter.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/BinaryPropertyListWriter.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/BinaryPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/PropertyListFormatException.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/PropertyListFormatException.html: Added supports for settings * DiscImageChef/Commands/Configure.cs: Added support for settings. * DiscImageChef/Core/Statistics.cs: * DiscImageChef/Commands/Verify.cs: * DiscImageChef/Commands/Entropy.cs: * DiscImageChef/Commands/Formats.cs: * DiscImageChef/Commands/PrintHex.cs: * DiscImageChef/Commands/MediaInfo.cs: * DiscImageChef/Commands/Statistics.cs: Added statistics. * DiscImageChef.Decoders/SCSI/Inquiry.cs: Corrected bug on inquiry decoding. * DiscImageChef.Decoders/SCSI/Modes.cs: Corrected bug on decoding mode page 2Ah without write performance descriptors. Corrected bug when there is a vendor page 0 in mode sense decoding. * DiscImageChef.Devices/Device/Constructor.cs: Corrected detecting USB or FireWire attached CD/DVD/BD and tape drives. Try ATA identify on USB or FireWire that don't have SCSI INQUIRY. * DiscImageChef.DiscImages/CDRWin.cs: Corrected CD-ROM XA vs CD-ROM detection. * DiscImageChef.Partitions/AppleMap.cs: Corrected big endian working. Added debug output. * DiscImageChef.sln: Added supports for settings. * DiscImageChef/Commands/Decode.cs: * DiscImageChef/Commands/Analyze.cs: * DiscImageChef/Commands/Compare.cs: * DiscImageChef/Commands/Checksum.cs: * DiscImageChef/Commands/Benchmark.cs: * DiscImageChef/Commands/DeviceInfo.cs: * DiscImageChef/Commands/CreateSidecar.cs: Added statistics. * DiscImageChef/Commands/DeviceReport.cs: Added statistics. Correct handling empty inquiry string fields. Suppose it is not removable, til proved wrong. Corrected MODE SENSE (6/10) detection and calling order. If device is MMC type but reports neither mode page 2Ah neither GET CONFIGURATION, try all CDs (old drives work like that). Try reading Lead-In and Lead-Out in Audio CD using Audio READ CD commands. Corrected READ LONG information handling, some drives return 2s-complement in 32 bit. Upper 16 bits are ignored. Added support for DVD raw block (37856 bytes). Check READ LONG up to 36 times the cooked block size. That should be enough to detect huge blocked media (like DVD and BD) without taking ages. If READ LONG size had to be bruteforced, and debug is activated, save the result. * DiscImageChef/Commands/DumpMedia.cs: Added statistics. Corrected READ LONG information handling, some drives return 2s-complement in 32 bit. Upper 16 bits are ignored. Start trying with 64 blocks at a time. Some drives report to be able to read 255 at a time, but they really don't, they take a lot longer to read. * DiscImageChef/Commands/MediaScan.cs: Added statistics. Start trying with 64 blocks at a time. Some drives report to be able to read 255 at a time, but they really don't, they take a lot longer to read. * DiscImageChef/DiscImageChef.csproj: Added support for settings. Added statistics. * DiscImageChef/Main.cs: * DiscImageChef/Options.cs: Added support for settings. Added statistics.
2016-02-03 18:58:11 +00:00
pg.PageResponse = new byte[modeResponse.Length - offset];
2015-10-31 19:41:58 +00:00
Array.Copy(modeResponse, offset, pg.PageResponse, 0, pg.PageResponse.Length);
* commandline: * DiscImageChef.Settings/Settings.cs: * DiscImageChef.Settings/docs/README.txt: * DiscImageChef.Settings/packages.config: * DiscImageChef.Settings/docs/LICENSE.txt: * DiscImageChef.Settings/docs/ChangeLog.txt: * DiscImageChef.Settings/docs/mono/index.xml: * DiscImageChef.Settings/docs/html/index.html: * DiscImageChef.Settings/Properties/AssemblyInfo.cs: * DiscImageChef.Settings/DiscImageChef.Settings.csproj: * DiscImageChef.Settings/docs/mono/ns-Claunia.PropertyList.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/UID.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/UID.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSSet.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/index.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSSet.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSDate.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSData.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSDate.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSData.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSArray.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSNumber.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSString.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSObject.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSArray.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSNumber.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSString.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSObject.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSDictionary.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSDictionary.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/PropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/PropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/XmlPropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/XmlPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/ASCIIPropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/ASCIIPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/BinaryPropertyListParser.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/BinaryPropertyListWriter.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/BinaryPropertyListWriter.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/BinaryPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/PropertyListFormatException.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/PropertyListFormatException.html: Added supports for settings * DiscImageChef/Commands/Configure.cs: Added support for settings. * DiscImageChef/Core/Statistics.cs: * DiscImageChef/Commands/Verify.cs: * DiscImageChef/Commands/Entropy.cs: * DiscImageChef/Commands/Formats.cs: * DiscImageChef/Commands/PrintHex.cs: * DiscImageChef/Commands/MediaInfo.cs: * DiscImageChef/Commands/Statistics.cs: Added statistics. * DiscImageChef.Decoders/SCSI/Inquiry.cs: Corrected bug on inquiry decoding. * DiscImageChef.Decoders/SCSI/Modes.cs: Corrected bug on decoding mode page 2Ah without write performance descriptors. Corrected bug when there is a vendor page 0 in mode sense decoding. * DiscImageChef.Devices/Device/Constructor.cs: Corrected detecting USB or FireWire attached CD/DVD/BD and tape drives. Try ATA identify on USB or FireWire that don't have SCSI INQUIRY. * DiscImageChef.DiscImages/CDRWin.cs: Corrected CD-ROM XA vs CD-ROM detection. * DiscImageChef.Partitions/AppleMap.cs: Corrected big endian working. Added debug output. * DiscImageChef.sln: Added supports for settings. * DiscImageChef/Commands/Decode.cs: * DiscImageChef/Commands/Analyze.cs: * DiscImageChef/Commands/Compare.cs: * DiscImageChef/Commands/Checksum.cs: * DiscImageChef/Commands/Benchmark.cs: * DiscImageChef/Commands/DeviceInfo.cs: * DiscImageChef/Commands/CreateSidecar.cs: Added statistics. * DiscImageChef/Commands/DeviceReport.cs: Added statistics. Correct handling empty inquiry string fields. Suppose it is not removable, til proved wrong. Corrected MODE SENSE (6/10) detection and calling order. If device is MMC type but reports neither mode page 2Ah neither GET CONFIGURATION, try all CDs (old drives work like that). Try reading Lead-In and Lead-Out in Audio CD using Audio READ CD commands. Corrected READ LONG information handling, some drives return 2s-complement in 32 bit. Upper 16 bits are ignored. Added support for DVD raw block (37856 bytes). Check READ LONG up to 36 times the cooked block size. That should be enough to detect huge blocked media (like DVD and BD) without taking ages. If READ LONG size had to be bruteforced, and debug is activated, save the result. * DiscImageChef/Commands/DumpMedia.cs: Added statistics. Corrected READ LONG information handling, some drives return 2s-complement in 32 bit. Upper 16 bits are ignored. Start trying with 64 blocks at a time. Some drives report to be able to read 255 at a time, but they really don't, they take a lot longer to read. * DiscImageChef/Commands/MediaScan.cs: Added statistics. Start trying with 64 blocks at a time. Some drives report to be able to read 255 at a time, but they really don't, they take a lot longer to read. * DiscImageChef/DiscImageChef.csproj: Added support for settings. Added statistics. * DiscImageChef/Main.cs: * DiscImageChef/Options.cs: Added support for settings. Added statistics.
2016-02-03 18:58:11 +00:00
pg.Page = 0;
pg.Subpage = 0;
2015-10-31 19:41:58 +00:00
offset += pg.PageResponse.Length;
}
else
{
2016-04-19 02:11:47 +01:00
if(isSubpage)
* commandline: * DiscImageChef.Settings/Settings.cs: * DiscImageChef.Settings/docs/README.txt: * DiscImageChef.Settings/packages.config: * DiscImageChef.Settings/docs/LICENSE.txt: * DiscImageChef.Settings/docs/ChangeLog.txt: * DiscImageChef.Settings/docs/mono/index.xml: * DiscImageChef.Settings/docs/html/index.html: * DiscImageChef.Settings/Properties/AssemblyInfo.cs: * DiscImageChef.Settings/DiscImageChef.Settings.csproj: * DiscImageChef.Settings/docs/mono/ns-Claunia.PropertyList.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/UID.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/UID.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSSet.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/index.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSSet.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSDate.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSData.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSDate.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSData.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSArray.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSNumber.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSString.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSObject.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSArray.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSNumber.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSString.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSObject.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSDictionary.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSDictionary.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/PropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/PropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/XmlPropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/XmlPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/ASCIIPropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/ASCIIPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/BinaryPropertyListParser.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/BinaryPropertyListWriter.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/BinaryPropertyListWriter.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/BinaryPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/PropertyListFormatException.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/PropertyListFormatException.html: Added supports for settings * DiscImageChef/Commands/Configure.cs: Added support for settings. * DiscImageChef/Core/Statistics.cs: * DiscImageChef/Commands/Verify.cs: * DiscImageChef/Commands/Entropy.cs: * DiscImageChef/Commands/Formats.cs: * DiscImageChef/Commands/PrintHex.cs: * DiscImageChef/Commands/MediaInfo.cs: * DiscImageChef/Commands/Statistics.cs: Added statistics. * DiscImageChef.Decoders/SCSI/Inquiry.cs: Corrected bug on inquiry decoding. * DiscImageChef.Decoders/SCSI/Modes.cs: Corrected bug on decoding mode page 2Ah without write performance descriptors. Corrected bug when there is a vendor page 0 in mode sense decoding. * DiscImageChef.Devices/Device/Constructor.cs: Corrected detecting USB or FireWire attached CD/DVD/BD and tape drives. Try ATA identify on USB or FireWire that don't have SCSI INQUIRY. * DiscImageChef.DiscImages/CDRWin.cs: Corrected CD-ROM XA vs CD-ROM detection. * DiscImageChef.Partitions/AppleMap.cs: Corrected big endian working. Added debug output. * DiscImageChef.sln: Added supports for settings. * DiscImageChef/Commands/Decode.cs: * DiscImageChef/Commands/Analyze.cs: * DiscImageChef/Commands/Compare.cs: * DiscImageChef/Commands/Checksum.cs: * DiscImageChef/Commands/Benchmark.cs: * DiscImageChef/Commands/DeviceInfo.cs: * DiscImageChef/Commands/CreateSidecar.cs: Added statistics. * DiscImageChef/Commands/DeviceReport.cs: Added statistics. Correct handling empty inquiry string fields. Suppose it is not removable, til proved wrong. Corrected MODE SENSE (6/10) detection and calling order. If device is MMC type but reports neither mode page 2Ah neither GET CONFIGURATION, try all CDs (old drives work like that). Try reading Lead-In and Lead-Out in Audio CD using Audio READ CD commands. Corrected READ LONG information handling, some drives return 2s-complement in 32 bit. Upper 16 bits are ignored. Added support for DVD raw block (37856 bytes). Check READ LONG up to 36 times the cooked block size. That should be enough to detect huge blocked media (like DVD and BD) without taking ages. If READ LONG size had to be bruteforced, and debug is activated, save the result. * DiscImageChef/Commands/DumpMedia.cs: Added statistics. Corrected READ LONG information handling, some drives return 2s-complement in 32 bit. Upper 16 bits are ignored. Start trying with 64 blocks at a time. Some drives report to be able to read 255 at a time, but they really don't, they take a lot longer to read. * DiscImageChef/Commands/MediaScan.cs: Added statistics. Start trying with 64 blocks at a time. Some drives report to be able to read 255 at a time, but they really don't, they take a lot longer to read. * DiscImageChef/DiscImageChef.csproj: Added support for settings. Added statistics. * DiscImageChef/Main.cs: * DiscImageChef/Options.cs: Added support for settings. Added statistics.
2016-02-03 18:58:11 +00:00
{
pg.PageResponse = new byte[(modeResponse[offset + 2] << 8) + modeResponse[offset + 3] + 4];
2016-04-19 02:11:47 +01:00
if((pg.PageResponse.Length + offset) > modeResponse.Length)
* commandline: * DiscImageChef.Settings/Settings.cs: * DiscImageChef.Settings/docs/README.txt: * DiscImageChef.Settings/packages.config: * DiscImageChef.Settings/docs/LICENSE.txt: * DiscImageChef.Settings/docs/ChangeLog.txt: * DiscImageChef.Settings/docs/mono/index.xml: * DiscImageChef.Settings/docs/html/index.html: * DiscImageChef.Settings/Properties/AssemblyInfo.cs: * DiscImageChef.Settings/DiscImageChef.Settings.csproj: * DiscImageChef.Settings/docs/mono/ns-Claunia.PropertyList.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/UID.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/UID.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSSet.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/index.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSSet.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSDate.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSData.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSDate.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSData.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSArray.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSNumber.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSString.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSObject.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSArray.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSNumber.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSString.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSObject.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSDictionary.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSDictionary.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/PropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/PropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/XmlPropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/XmlPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/ASCIIPropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/ASCIIPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/BinaryPropertyListParser.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/BinaryPropertyListWriter.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/BinaryPropertyListWriter.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/BinaryPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/PropertyListFormatException.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/PropertyListFormatException.html: Added supports for settings * DiscImageChef/Commands/Configure.cs: Added support for settings. * DiscImageChef/Core/Statistics.cs: * DiscImageChef/Commands/Verify.cs: * DiscImageChef/Commands/Entropy.cs: * DiscImageChef/Commands/Formats.cs: * DiscImageChef/Commands/PrintHex.cs: * DiscImageChef/Commands/MediaInfo.cs: * DiscImageChef/Commands/Statistics.cs: Added statistics. * DiscImageChef.Decoders/SCSI/Inquiry.cs: Corrected bug on inquiry decoding. * DiscImageChef.Decoders/SCSI/Modes.cs: Corrected bug on decoding mode page 2Ah without write performance descriptors. Corrected bug when there is a vendor page 0 in mode sense decoding. * DiscImageChef.Devices/Device/Constructor.cs: Corrected detecting USB or FireWire attached CD/DVD/BD and tape drives. Try ATA identify on USB or FireWire that don't have SCSI INQUIRY. * DiscImageChef.DiscImages/CDRWin.cs: Corrected CD-ROM XA vs CD-ROM detection. * DiscImageChef.Partitions/AppleMap.cs: Corrected big endian working. Added debug output. * DiscImageChef.sln: Added supports for settings. * DiscImageChef/Commands/Decode.cs: * DiscImageChef/Commands/Analyze.cs: * DiscImageChef/Commands/Compare.cs: * DiscImageChef/Commands/Checksum.cs: * DiscImageChef/Commands/Benchmark.cs: * DiscImageChef/Commands/DeviceInfo.cs: * DiscImageChef/Commands/CreateSidecar.cs: Added statistics. * DiscImageChef/Commands/DeviceReport.cs: Added statistics. Correct handling empty inquiry string fields. Suppose it is not removable, til proved wrong. Corrected MODE SENSE (6/10) detection and calling order. If device is MMC type but reports neither mode page 2Ah neither GET CONFIGURATION, try all CDs (old drives work like that). Try reading Lead-In and Lead-Out in Audio CD using Audio READ CD commands. Corrected READ LONG information handling, some drives return 2s-complement in 32 bit. Upper 16 bits are ignored. Added support for DVD raw block (37856 bytes). Check READ LONG up to 36 times the cooked block size. That should be enough to detect huge blocked media (like DVD and BD) without taking ages. If READ LONG size had to be bruteforced, and debug is activated, save the result. * DiscImageChef/Commands/DumpMedia.cs: Added statistics. Corrected READ LONG information handling, some drives return 2s-complement in 32 bit. Upper 16 bits are ignored. Start trying with 64 blocks at a time. Some drives report to be able to read 255 at a time, but they really don't, they take a lot longer to read. * DiscImageChef/Commands/MediaScan.cs: Added statistics. Start trying with 64 blocks at a time. Some drives report to be able to read 255 at a time, but they really don't, they take a lot longer to read. * DiscImageChef/DiscImageChef.csproj: Added support for settings. Added statistics. * DiscImageChef/Main.cs: * DiscImageChef/Options.cs: Added support for settings. Added statistics.
2016-02-03 18:58:11 +00:00
return decoded;
Array.Copy(modeResponse, offset, pg.PageResponse, 0, pg.PageResponse.Length);
pg.Page = (byte)(modeResponse[offset] & 0x3F);
pg.Subpage = modeResponse[offset + 1];
offset += pg.PageResponse.Length;
}
else
{
pg.PageResponse = new byte[modeResponse[offset + 1] + 2];
2016-04-19 02:11:47 +01:00
if((pg.PageResponse.Length + offset) > modeResponse.Length)
* commandline: * DiscImageChef.Settings/Settings.cs: * DiscImageChef.Settings/docs/README.txt: * DiscImageChef.Settings/packages.config: * DiscImageChef.Settings/docs/LICENSE.txt: * DiscImageChef.Settings/docs/ChangeLog.txt: * DiscImageChef.Settings/docs/mono/index.xml: * DiscImageChef.Settings/docs/html/index.html: * DiscImageChef.Settings/Properties/AssemblyInfo.cs: * DiscImageChef.Settings/DiscImageChef.Settings.csproj: * DiscImageChef.Settings/docs/mono/ns-Claunia.PropertyList.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/UID.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/UID.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSSet.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/index.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSSet.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSDate.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSData.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSDate.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSData.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSArray.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSNumber.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSString.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSObject.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSArray.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSNumber.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSString.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSObject.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSDictionary.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSDictionary.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/PropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/PropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/XmlPropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/XmlPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/ASCIIPropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/ASCIIPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/BinaryPropertyListParser.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/BinaryPropertyListWriter.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/BinaryPropertyListWriter.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/BinaryPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/PropertyListFormatException.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/PropertyListFormatException.html: Added supports for settings * DiscImageChef/Commands/Configure.cs: Added support for settings. * DiscImageChef/Core/Statistics.cs: * DiscImageChef/Commands/Verify.cs: * DiscImageChef/Commands/Entropy.cs: * DiscImageChef/Commands/Formats.cs: * DiscImageChef/Commands/PrintHex.cs: * DiscImageChef/Commands/MediaInfo.cs: * DiscImageChef/Commands/Statistics.cs: Added statistics. * DiscImageChef.Decoders/SCSI/Inquiry.cs: Corrected bug on inquiry decoding. * DiscImageChef.Decoders/SCSI/Modes.cs: Corrected bug on decoding mode page 2Ah without write performance descriptors. Corrected bug when there is a vendor page 0 in mode sense decoding. * DiscImageChef.Devices/Device/Constructor.cs: Corrected detecting USB or FireWire attached CD/DVD/BD and tape drives. Try ATA identify on USB or FireWire that don't have SCSI INQUIRY. * DiscImageChef.DiscImages/CDRWin.cs: Corrected CD-ROM XA vs CD-ROM detection. * DiscImageChef.Partitions/AppleMap.cs: Corrected big endian working. Added debug output. * DiscImageChef.sln: Added supports for settings. * DiscImageChef/Commands/Decode.cs: * DiscImageChef/Commands/Analyze.cs: * DiscImageChef/Commands/Compare.cs: * DiscImageChef/Commands/Checksum.cs: * DiscImageChef/Commands/Benchmark.cs: * DiscImageChef/Commands/DeviceInfo.cs: * DiscImageChef/Commands/CreateSidecar.cs: Added statistics. * DiscImageChef/Commands/DeviceReport.cs: Added statistics. Correct handling empty inquiry string fields. Suppose it is not removable, til proved wrong. Corrected MODE SENSE (6/10) detection and calling order. If device is MMC type but reports neither mode page 2Ah neither GET CONFIGURATION, try all CDs (old drives work like that). Try reading Lead-In and Lead-Out in Audio CD using Audio READ CD commands. Corrected READ LONG information handling, some drives return 2s-complement in 32 bit. Upper 16 bits are ignored. Added support for DVD raw block (37856 bytes). Check READ LONG up to 36 times the cooked block size. That should be enough to detect huge blocked media (like DVD and BD) without taking ages. If READ LONG size had to be bruteforced, and debug is activated, save the result. * DiscImageChef/Commands/DumpMedia.cs: Added statistics. Corrected READ LONG information handling, some drives return 2s-complement in 32 bit. Upper 16 bits are ignored. Start trying with 64 blocks at a time. Some drives report to be able to read 255 at a time, but they really don't, they take a lot longer to read. * DiscImageChef/Commands/MediaScan.cs: Added statistics. Start trying with 64 blocks at a time. Some drives report to be able to read 255 at a time, but they really don't, they take a lot longer to read. * DiscImageChef/DiscImageChef.csproj: Added support for settings. Added statistics. * DiscImageChef/Main.cs: * DiscImageChef/Options.cs: Added support for settings. Added statistics.
2016-02-03 18:58:11 +00:00
return decoded;
Array.Copy(modeResponse, offset, pg.PageResponse, 0, pg.PageResponse.Length);
pg.Page = (byte)(modeResponse[offset] & 0x3F);
pg.Subpage = 0;
offset += pg.PageResponse.Length;
}
2015-10-31 19:41:58 +00:00
}
listpages.Add(pg);
}
decoded.Pages = listpages.ToArray();
return decoded;
}
public static DecodedMode? DecodeMode10(byte[] modeResponse, PeripheralDeviceTypes deviceType)
{
ModeHeader? hdr = DecodeModeHeader10(modeResponse, deviceType);
2016-04-19 02:11:47 +01:00
if(!hdr.HasValue)
2015-10-31 19:41:58 +00:00
return null;
DecodedMode decoded = new DecodedMode();
decoded.Header = hdr.Value;
bool longlba = (modeResponse[4] & 0x01) == 0x01;
int offset;
int blkDrLength = 0;
2016-04-19 02:11:47 +01:00
if(decoded.Header.BlockDescriptors != null)
blkDrLength = decoded.Header.BlockDescriptors.Length;
2015-10-31 19:41:58 +00:00
2016-04-19 02:11:47 +01:00
if(longlba)
offset = 8 + blkDrLength * 16;
2015-10-31 19:41:58 +00:00
else
offset = 8 + blkDrLength * 8;
2015-10-31 19:41:58 +00:00
int length = (modeResponse[0] << 8);
length += modeResponse[1];
length += 2;
2015-10-31 19:41:58 +00:00
2016-04-19 02:11:47 +01:00
if(length != modeResponse.Length)
2015-10-31 19:41:58 +00:00
return decoded;
List<ModePage> listpages = new List<ModePage>();
2015-10-31 19:41:58 +00:00
2016-04-19 02:11:47 +01:00
while(offset < modeResponse.Length)
2015-10-31 19:41:58 +00:00
{
bool isSubpage = (modeResponse[offset] & 0x40) == 0x40;
ModePage pg = new ModePage();
* commandline: * DiscImageChef.Settings/Settings.cs: * DiscImageChef.Settings/docs/README.txt: * DiscImageChef.Settings/packages.config: * DiscImageChef.Settings/docs/LICENSE.txt: * DiscImageChef.Settings/docs/ChangeLog.txt: * DiscImageChef.Settings/docs/mono/index.xml: * DiscImageChef.Settings/docs/html/index.html: * DiscImageChef.Settings/Properties/AssemblyInfo.cs: * DiscImageChef.Settings/DiscImageChef.Settings.csproj: * DiscImageChef.Settings/docs/mono/ns-Claunia.PropertyList.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/UID.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/UID.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSSet.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/index.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSSet.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSDate.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSData.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSDate.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSData.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSArray.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSNumber.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSString.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSObject.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSArray.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSNumber.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSString.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSObject.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSDictionary.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSDictionary.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/PropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/PropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/XmlPropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/XmlPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/ASCIIPropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/ASCIIPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/BinaryPropertyListParser.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/BinaryPropertyListWriter.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/BinaryPropertyListWriter.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/BinaryPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/PropertyListFormatException.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/PropertyListFormatException.html: Added supports for settings * DiscImageChef/Commands/Configure.cs: Added support for settings. * DiscImageChef/Core/Statistics.cs: * DiscImageChef/Commands/Verify.cs: * DiscImageChef/Commands/Entropy.cs: * DiscImageChef/Commands/Formats.cs: * DiscImageChef/Commands/PrintHex.cs: * DiscImageChef/Commands/MediaInfo.cs: * DiscImageChef/Commands/Statistics.cs: Added statistics. * DiscImageChef.Decoders/SCSI/Inquiry.cs: Corrected bug on inquiry decoding. * DiscImageChef.Decoders/SCSI/Modes.cs: Corrected bug on decoding mode page 2Ah without write performance descriptors. Corrected bug when there is a vendor page 0 in mode sense decoding. * DiscImageChef.Devices/Device/Constructor.cs: Corrected detecting USB or FireWire attached CD/DVD/BD and tape drives. Try ATA identify on USB or FireWire that don't have SCSI INQUIRY. * DiscImageChef.DiscImages/CDRWin.cs: Corrected CD-ROM XA vs CD-ROM detection. * DiscImageChef.Partitions/AppleMap.cs: Corrected big endian working. Added debug output. * DiscImageChef.sln: Added supports for settings. * DiscImageChef/Commands/Decode.cs: * DiscImageChef/Commands/Analyze.cs: * DiscImageChef/Commands/Compare.cs: * DiscImageChef/Commands/Checksum.cs: * DiscImageChef/Commands/Benchmark.cs: * DiscImageChef/Commands/DeviceInfo.cs: * DiscImageChef/Commands/CreateSidecar.cs: Added statistics. * DiscImageChef/Commands/DeviceReport.cs: Added statistics. Correct handling empty inquiry string fields. Suppose it is not removable, til proved wrong. Corrected MODE SENSE (6/10) detection and calling order. If device is MMC type but reports neither mode page 2Ah neither GET CONFIGURATION, try all CDs (old drives work like that). Try reading Lead-In and Lead-Out in Audio CD using Audio READ CD commands. Corrected READ LONG information handling, some drives return 2s-complement in 32 bit. Upper 16 bits are ignored. Added support for DVD raw block (37856 bytes). Check READ LONG up to 36 times the cooked block size. That should be enough to detect huge blocked media (like DVD and BD) without taking ages. If READ LONG size had to be bruteforced, and debug is activated, save the result. * DiscImageChef/Commands/DumpMedia.cs: Added statistics. Corrected READ LONG information handling, some drives return 2s-complement in 32 bit. Upper 16 bits are ignored. Start trying with 64 blocks at a time. Some drives report to be able to read 255 at a time, but they really don't, they take a lot longer to read. * DiscImageChef/Commands/MediaScan.cs: Added statistics. Start trying with 64 blocks at a time. Some drives report to be able to read 255 at a time, but they really don't, they take a lot longer to read. * DiscImageChef/DiscImageChef.csproj: Added support for settings. Added statistics. * DiscImageChef/Main.cs: * DiscImageChef/Options.cs: Added support for settings. Added statistics.
2016-02-03 18:58:11 +00:00
byte pageNo = (byte)(modeResponse[offset] & 0x3F);
2015-10-31 19:41:58 +00:00
2016-04-19 02:11:47 +01:00
if(pageNo == 0)
2015-10-31 19:41:58 +00:00
{
* commandline: * DiscImageChef.Settings/Settings.cs: * DiscImageChef.Settings/docs/README.txt: * DiscImageChef.Settings/packages.config: * DiscImageChef.Settings/docs/LICENSE.txt: * DiscImageChef.Settings/docs/ChangeLog.txt: * DiscImageChef.Settings/docs/mono/index.xml: * DiscImageChef.Settings/docs/html/index.html: * DiscImageChef.Settings/Properties/AssemblyInfo.cs: * DiscImageChef.Settings/DiscImageChef.Settings.csproj: * DiscImageChef.Settings/docs/mono/ns-Claunia.PropertyList.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/UID.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/UID.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSSet.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/index.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSSet.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSDate.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSData.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSDate.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSData.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSArray.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSNumber.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSString.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSObject.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSArray.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSNumber.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSString.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSObject.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSDictionary.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSDictionary.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/PropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/PropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/XmlPropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/XmlPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/ASCIIPropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/ASCIIPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/BinaryPropertyListParser.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/BinaryPropertyListWriter.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/BinaryPropertyListWriter.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/BinaryPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/PropertyListFormatException.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/PropertyListFormatException.html: Added supports for settings * DiscImageChef/Commands/Configure.cs: Added support for settings. * DiscImageChef/Core/Statistics.cs: * DiscImageChef/Commands/Verify.cs: * DiscImageChef/Commands/Entropy.cs: * DiscImageChef/Commands/Formats.cs: * DiscImageChef/Commands/PrintHex.cs: * DiscImageChef/Commands/MediaInfo.cs: * DiscImageChef/Commands/Statistics.cs: Added statistics. * DiscImageChef.Decoders/SCSI/Inquiry.cs: Corrected bug on inquiry decoding. * DiscImageChef.Decoders/SCSI/Modes.cs: Corrected bug on decoding mode page 2Ah without write performance descriptors. Corrected bug when there is a vendor page 0 in mode sense decoding. * DiscImageChef.Devices/Device/Constructor.cs: Corrected detecting USB or FireWire attached CD/DVD/BD and tape drives. Try ATA identify on USB or FireWire that don't have SCSI INQUIRY. * DiscImageChef.DiscImages/CDRWin.cs: Corrected CD-ROM XA vs CD-ROM detection. * DiscImageChef.Partitions/AppleMap.cs: Corrected big endian working. Added debug output. * DiscImageChef.sln: Added supports for settings. * DiscImageChef/Commands/Decode.cs: * DiscImageChef/Commands/Analyze.cs: * DiscImageChef/Commands/Compare.cs: * DiscImageChef/Commands/Checksum.cs: * DiscImageChef/Commands/Benchmark.cs: * DiscImageChef/Commands/DeviceInfo.cs: * DiscImageChef/Commands/CreateSidecar.cs: Added statistics. * DiscImageChef/Commands/DeviceReport.cs: Added statistics. Correct handling empty inquiry string fields. Suppose it is not removable, til proved wrong. Corrected MODE SENSE (6/10) detection and calling order. If device is MMC type but reports neither mode page 2Ah neither GET CONFIGURATION, try all CDs (old drives work like that). Try reading Lead-In and Lead-Out in Audio CD using Audio READ CD commands. Corrected READ LONG information handling, some drives return 2s-complement in 32 bit. Upper 16 bits are ignored. Added support for DVD raw block (37856 bytes). Check READ LONG up to 36 times the cooked block size. That should be enough to detect huge blocked media (like DVD and BD) without taking ages. If READ LONG size had to be bruteforced, and debug is activated, save the result. * DiscImageChef/Commands/DumpMedia.cs: Added statistics. Corrected READ LONG information handling, some drives return 2s-complement in 32 bit. Upper 16 bits are ignored. Start trying with 64 blocks at a time. Some drives report to be able to read 255 at a time, but they really don't, they take a lot longer to read. * DiscImageChef/Commands/MediaScan.cs: Added statistics. Start trying with 64 blocks at a time. Some drives report to be able to read 255 at a time, but they really don't, they take a lot longer to read. * DiscImageChef/DiscImageChef.csproj: Added support for settings. Added statistics. * DiscImageChef/Main.cs: * DiscImageChef/Options.cs: Added support for settings. Added statistics.
2016-02-03 18:58:11 +00:00
pg.PageResponse = new byte[modeResponse.Length - offset];
2015-10-31 19:41:58 +00:00
Array.Copy(modeResponse, offset, pg.PageResponse, 0, pg.PageResponse.Length);
* commandline: * DiscImageChef.Settings/Settings.cs: * DiscImageChef.Settings/docs/README.txt: * DiscImageChef.Settings/packages.config: * DiscImageChef.Settings/docs/LICENSE.txt: * DiscImageChef.Settings/docs/ChangeLog.txt: * DiscImageChef.Settings/docs/mono/index.xml: * DiscImageChef.Settings/docs/html/index.html: * DiscImageChef.Settings/Properties/AssemblyInfo.cs: * DiscImageChef.Settings/DiscImageChef.Settings.csproj: * DiscImageChef.Settings/docs/mono/ns-Claunia.PropertyList.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/UID.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/UID.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSSet.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/index.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSSet.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSDate.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSData.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSDate.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSData.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSArray.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSNumber.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSString.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSObject.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSArray.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSNumber.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSString.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSObject.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSDictionary.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSDictionary.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/PropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/PropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/XmlPropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/XmlPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/ASCIIPropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/ASCIIPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/BinaryPropertyListParser.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/BinaryPropertyListWriter.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/BinaryPropertyListWriter.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/BinaryPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/PropertyListFormatException.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/PropertyListFormatException.html: Added supports for settings * DiscImageChef/Commands/Configure.cs: Added support for settings. * DiscImageChef/Core/Statistics.cs: * DiscImageChef/Commands/Verify.cs: * DiscImageChef/Commands/Entropy.cs: * DiscImageChef/Commands/Formats.cs: * DiscImageChef/Commands/PrintHex.cs: * DiscImageChef/Commands/MediaInfo.cs: * DiscImageChef/Commands/Statistics.cs: Added statistics. * DiscImageChef.Decoders/SCSI/Inquiry.cs: Corrected bug on inquiry decoding. * DiscImageChef.Decoders/SCSI/Modes.cs: Corrected bug on decoding mode page 2Ah without write performance descriptors. Corrected bug when there is a vendor page 0 in mode sense decoding. * DiscImageChef.Devices/Device/Constructor.cs: Corrected detecting USB or FireWire attached CD/DVD/BD and tape drives. Try ATA identify on USB or FireWire that don't have SCSI INQUIRY. * DiscImageChef.DiscImages/CDRWin.cs: Corrected CD-ROM XA vs CD-ROM detection. * DiscImageChef.Partitions/AppleMap.cs: Corrected big endian working. Added debug output. * DiscImageChef.sln: Added supports for settings. * DiscImageChef/Commands/Decode.cs: * DiscImageChef/Commands/Analyze.cs: * DiscImageChef/Commands/Compare.cs: * DiscImageChef/Commands/Checksum.cs: * DiscImageChef/Commands/Benchmark.cs: * DiscImageChef/Commands/DeviceInfo.cs: * DiscImageChef/Commands/CreateSidecar.cs: Added statistics. * DiscImageChef/Commands/DeviceReport.cs: Added statistics. Correct handling empty inquiry string fields. Suppose it is not removable, til proved wrong. Corrected MODE SENSE (6/10) detection and calling order. If device is MMC type but reports neither mode page 2Ah neither GET CONFIGURATION, try all CDs (old drives work like that). Try reading Lead-In and Lead-Out in Audio CD using Audio READ CD commands. Corrected READ LONG information handling, some drives return 2s-complement in 32 bit. Upper 16 bits are ignored. Added support for DVD raw block (37856 bytes). Check READ LONG up to 36 times the cooked block size. That should be enough to detect huge blocked media (like DVD and BD) without taking ages. If READ LONG size had to be bruteforced, and debug is activated, save the result. * DiscImageChef/Commands/DumpMedia.cs: Added statistics. Corrected READ LONG information handling, some drives return 2s-complement in 32 bit. Upper 16 bits are ignored. Start trying with 64 blocks at a time. Some drives report to be able to read 255 at a time, but they really don't, they take a lot longer to read. * DiscImageChef/Commands/MediaScan.cs: Added statistics. Start trying with 64 blocks at a time. Some drives report to be able to read 255 at a time, but they really don't, they take a lot longer to read. * DiscImageChef/DiscImageChef.csproj: Added support for settings. Added statistics. * DiscImageChef/Main.cs: * DiscImageChef/Options.cs: Added support for settings. Added statistics.
2016-02-03 18:58:11 +00:00
pg.Page = 0;
pg.Subpage = 0;
2015-10-31 19:41:58 +00:00
offset += pg.PageResponse.Length;
}
else
{
2016-04-19 02:11:47 +01:00
if(isSubpage)
* commandline: * DiscImageChef.Settings/Settings.cs: * DiscImageChef.Settings/docs/README.txt: * DiscImageChef.Settings/packages.config: * DiscImageChef.Settings/docs/LICENSE.txt: * DiscImageChef.Settings/docs/ChangeLog.txt: * DiscImageChef.Settings/docs/mono/index.xml: * DiscImageChef.Settings/docs/html/index.html: * DiscImageChef.Settings/Properties/AssemblyInfo.cs: * DiscImageChef.Settings/DiscImageChef.Settings.csproj: * DiscImageChef.Settings/docs/mono/ns-Claunia.PropertyList.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/UID.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/UID.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSSet.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/index.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSSet.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSDate.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSData.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSDate.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSData.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSArray.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSNumber.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSString.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSObject.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSArray.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSNumber.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSString.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSObject.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSDictionary.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSDictionary.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/PropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/PropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/XmlPropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/XmlPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/ASCIIPropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/ASCIIPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/BinaryPropertyListParser.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/BinaryPropertyListWriter.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/BinaryPropertyListWriter.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/BinaryPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/PropertyListFormatException.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/PropertyListFormatException.html: Added supports for settings * DiscImageChef/Commands/Configure.cs: Added support for settings. * DiscImageChef/Core/Statistics.cs: * DiscImageChef/Commands/Verify.cs: * DiscImageChef/Commands/Entropy.cs: * DiscImageChef/Commands/Formats.cs: * DiscImageChef/Commands/PrintHex.cs: * DiscImageChef/Commands/MediaInfo.cs: * DiscImageChef/Commands/Statistics.cs: Added statistics. * DiscImageChef.Decoders/SCSI/Inquiry.cs: Corrected bug on inquiry decoding. * DiscImageChef.Decoders/SCSI/Modes.cs: Corrected bug on decoding mode page 2Ah without write performance descriptors. Corrected bug when there is a vendor page 0 in mode sense decoding. * DiscImageChef.Devices/Device/Constructor.cs: Corrected detecting USB or FireWire attached CD/DVD/BD and tape drives. Try ATA identify on USB or FireWire that don't have SCSI INQUIRY. * DiscImageChef.DiscImages/CDRWin.cs: Corrected CD-ROM XA vs CD-ROM detection. * DiscImageChef.Partitions/AppleMap.cs: Corrected big endian working. Added debug output. * DiscImageChef.sln: Added supports for settings. * DiscImageChef/Commands/Decode.cs: * DiscImageChef/Commands/Analyze.cs: * DiscImageChef/Commands/Compare.cs: * DiscImageChef/Commands/Checksum.cs: * DiscImageChef/Commands/Benchmark.cs: * DiscImageChef/Commands/DeviceInfo.cs: * DiscImageChef/Commands/CreateSidecar.cs: Added statistics. * DiscImageChef/Commands/DeviceReport.cs: Added statistics. Correct handling empty inquiry string fields. Suppose it is not removable, til proved wrong. Corrected MODE SENSE (6/10) detection and calling order. If device is MMC type but reports neither mode page 2Ah neither GET CONFIGURATION, try all CDs (old drives work like that). Try reading Lead-In and Lead-Out in Audio CD using Audio READ CD commands. Corrected READ LONG information handling, some drives return 2s-complement in 32 bit. Upper 16 bits are ignored. Added support for DVD raw block (37856 bytes). Check READ LONG up to 36 times the cooked block size. That should be enough to detect huge blocked media (like DVD and BD) without taking ages. If READ LONG size had to be bruteforced, and debug is activated, save the result. * DiscImageChef/Commands/DumpMedia.cs: Added statistics. Corrected READ LONG information handling, some drives return 2s-complement in 32 bit. Upper 16 bits are ignored. Start trying with 64 blocks at a time. Some drives report to be able to read 255 at a time, but they really don't, they take a lot longer to read. * DiscImageChef/Commands/MediaScan.cs: Added statistics. Start trying with 64 blocks at a time. Some drives report to be able to read 255 at a time, but they really don't, they take a lot longer to read. * DiscImageChef/DiscImageChef.csproj: Added support for settings. Added statistics. * DiscImageChef/Main.cs: * DiscImageChef/Options.cs: Added support for settings. Added statistics.
2016-02-03 18:58:11 +00:00
{
pg.PageResponse = new byte[(modeResponse[offset + 2] << 8) + modeResponse[offset + 3] + 4];
2016-04-19 02:11:47 +01:00
if((pg.PageResponse.Length + offset) > modeResponse.Length)
* commandline: * DiscImageChef.Settings/Settings.cs: * DiscImageChef.Settings/docs/README.txt: * DiscImageChef.Settings/packages.config: * DiscImageChef.Settings/docs/LICENSE.txt: * DiscImageChef.Settings/docs/ChangeLog.txt: * DiscImageChef.Settings/docs/mono/index.xml: * DiscImageChef.Settings/docs/html/index.html: * DiscImageChef.Settings/Properties/AssemblyInfo.cs: * DiscImageChef.Settings/DiscImageChef.Settings.csproj: * DiscImageChef.Settings/docs/mono/ns-Claunia.PropertyList.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/UID.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/UID.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSSet.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/index.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSSet.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSDate.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSData.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSDate.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSData.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSArray.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSNumber.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSString.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSObject.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSArray.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSNumber.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSString.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSObject.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSDictionary.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSDictionary.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/PropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/PropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/XmlPropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/XmlPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/ASCIIPropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/ASCIIPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/BinaryPropertyListParser.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/BinaryPropertyListWriter.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/BinaryPropertyListWriter.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/BinaryPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/PropertyListFormatException.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/PropertyListFormatException.html: Added supports for settings * DiscImageChef/Commands/Configure.cs: Added support for settings. * DiscImageChef/Core/Statistics.cs: * DiscImageChef/Commands/Verify.cs: * DiscImageChef/Commands/Entropy.cs: * DiscImageChef/Commands/Formats.cs: * DiscImageChef/Commands/PrintHex.cs: * DiscImageChef/Commands/MediaInfo.cs: * DiscImageChef/Commands/Statistics.cs: Added statistics. * DiscImageChef.Decoders/SCSI/Inquiry.cs: Corrected bug on inquiry decoding. * DiscImageChef.Decoders/SCSI/Modes.cs: Corrected bug on decoding mode page 2Ah without write performance descriptors. Corrected bug when there is a vendor page 0 in mode sense decoding. * DiscImageChef.Devices/Device/Constructor.cs: Corrected detecting USB or FireWire attached CD/DVD/BD and tape drives. Try ATA identify on USB or FireWire that don't have SCSI INQUIRY. * DiscImageChef.DiscImages/CDRWin.cs: Corrected CD-ROM XA vs CD-ROM detection. * DiscImageChef.Partitions/AppleMap.cs: Corrected big endian working. Added debug output. * DiscImageChef.sln: Added supports for settings. * DiscImageChef/Commands/Decode.cs: * DiscImageChef/Commands/Analyze.cs: * DiscImageChef/Commands/Compare.cs: * DiscImageChef/Commands/Checksum.cs: * DiscImageChef/Commands/Benchmark.cs: * DiscImageChef/Commands/DeviceInfo.cs: * DiscImageChef/Commands/CreateSidecar.cs: Added statistics. * DiscImageChef/Commands/DeviceReport.cs: Added statistics. Correct handling empty inquiry string fields. Suppose it is not removable, til proved wrong. Corrected MODE SENSE (6/10) detection and calling order. If device is MMC type but reports neither mode page 2Ah neither GET CONFIGURATION, try all CDs (old drives work like that). Try reading Lead-In and Lead-Out in Audio CD using Audio READ CD commands. Corrected READ LONG information handling, some drives return 2s-complement in 32 bit. Upper 16 bits are ignored. Added support for DVD raw block (37856 bytes). Check READ LONG up to 36 times the cooked block size. That should be enough to detect huge blocked media (like DVD and BD) without taking ages. If READ LONG size had to be bruteforced, and debug is activated, save the result. * DiscImageChef/Commands/DumpMedia.cs: Added statistics. Corrected READ LONG information handling, some drives return 2s-complement in 32 bit. Upper 16 bits are ignored. Start trying with 64 blocks at a time. Some drives report to be able to read 255 at a time, but they really don't, they take a lot longer to read. * DiscImageChef/Commands/MediaScan.cs: Added statistics. Start trying with 64 blocks at a time. Some drives report to be able to read 255 at a time, but they really don't, they take a lot longer to read. * DiscImageChef/DiscImageChef.csproj: Added support for settings. Added statistics. * DiscImageChef/Main.cs: * DiscImageChef/Options.cs: Added support for settings. Added statistics.
2016-02-03 18:58:11 +00:00
return decoded;
* commandline: * DiscImageChef.Settings/Settings.cs: * DiscImageChef.Settings/docs/README.txt: * DiscImageChef.Settings/packages.config: * DiscImageChef.Settings/docs/LICENSE.txt: * DiscImageChef.Settings/docs/ChangeLog.txt: * DiscImageChef.Settings/docs/mono/index.xml: * DiscImageChef.Settings/docs/html/index.html: * DiscImageChef.Settings/Properties/AssemblyInfo.cs: * DiscImageChef.Settings/DiscImageChef.Settings.csproj: * DiscImageChef.Settings/docs/mono/ns-Claunia.PropertyList.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/UID.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/UID.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSSet.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/index.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSSet.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSDate.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSData.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSDate.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSData.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSArray.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSNumber.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSString.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSObject.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSArray.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSNumber.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSString.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSObject.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSDictionary.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSDictionary.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/PropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/PropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/XmlPropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/XmlPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/ASCIIPropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/ASCIIPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/BinaryPropertyListParser.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/BinaryPropertyListWriter.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/BinaryPropertyListWriter.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/BinaryPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/PropertyListFormatException.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/PropertyListFormatException.html: Added supports for settings * DiscImageChef/Commands/Configure.cs: Added support for settings. * DiscImageChef/Core/Statistics.cs: * DiscImageChef/Commands/Verify.cs: * DiscImageChef/Commands/Entropy.cs: * DiscImageChef/Commands/Formats.cs: * DiscImageChef/Commands/PrintHex.cs: * DiscImageChef/Commands/MediaInfo.cs: * DiscImageChef/Commands/Statistics.cs: Added statistics. * DiscImageChef.Decoders/SCSI/Inquiry.cs: Corrected bug on inquiry decoding. * DiscImageChef.Decoders/SCSI/Modes.cs: Corrected bug on decoding mode page 2Ah without write performance descriptors. Corrected bug when there is a vendor page 0 in mode sense decoding. * DiscImageChef.Devices/Device/Constructor.cs: Corrected detecting USB or FireWire attached CD/DVD/BD and tape drives. Try ATA identify on USB or FireWire that don't have SCSI INQUIRY. * DiscImageChef.DiscImages/CDRWin.cs: Corrected CD-ROM XA vs CD-ROM detection. * DiscImageChef.Partitions/AppleMap.cs: Corrected big endian working. Added debug output. * DiscImageChef.sln: Added supports for settings. * DiscImageChef/Commands/Decode.cs: * DiscImageChef/Commands/Analyze.cs: * DiscImageChef/Commands/Compare.cs: * DiscImageChef/Commands/Checksum.cs: * DiscImageChef/Commands/Benchmark.cs: * DiscImageChef/Commands/DeviceInfo.cs: * DiscImageChef/Commands/CreateSidecar.cs: Added statistics. * DiscImageChef/Commands/DeviceReport.cs: Added statistics. Correct handling empty inquiry string fields. Suppose it is not removable, til proved wrong. Corrected MODE SENSE (6/10) detection and calling order. If device is MMC type but reports neither mode page 2Ah neither GET CONFIGURATION, try all CDs (old drives work like that). Try reading Lead-In and Lead-Out in Audio CD using Audio READ CD commands. Corrected READ LONG information handling, some drives return 2s-complement in 32 bit. Upper 16 bits are ignored. Added support for DVD raw block (37856 bytes). Check READ LONG up to 36 times the cooked block size. That should be enough to detect huge blocked media (like DVD and BD) without taking ages. If READ LONG size had to be bruteforced, and debug is activated, save the result. * DiscImageChef/Commands/DumpMedia.cs: Added statistics. Corrected READ LONG information handling, some drives return 2s-complement in 32 bit. Upper 16 bits are ignored. Start trying with 64 blocks at a time. Some drives report to be able to read 255 at a time, but they really don't, they take a lot longer to read. * DiscImageChef/Commands/MediaScan.cs: Added statistics. Start trying with 64 blocks at a time. Some drives report to be able to read 255 at a time, but they really don't, they take a lot longer to read. * DiscImageChef/DiscImageChef.csproj: Added support for settings. Added statistics. * DiscImageChef/Main.cs: * DiscImageChef/Options.cs: Added support for settings. Added statistics.
2016-02-03 18:58:11 +00:00
Array.Copy(modeResponse, offset, pg.PageResponse, 0, pg.PageResponse.Length);
pg.Page = (byte)(modeResponse[offset] & 0x3F);
pg.Subpage = modeResponse[offset + 1];
offset += pg.PageResponse.Length;
}
else
{
pg.PageResponse = new byte[modeResponse[offset + 1] + 2];
2016-04-19 02:11:47 +01:00
if((pg.PageResponse.Length + offset) > modeResponse.Length)
* commandline: * DiscImageChef.Settings/Settings.cs: * DiscImageChef.Settings/docs/README.txt: * DiscImageChef.Settings/packages.config: * DiscImageChef.Settings/docs/LICENSE.txt: * DiscImageChef.Settings/docs/ChangeLog.txt: * DiscImageChef.Settings/docs/mono/index.xml: * DiscImageChef.Settings/docs/html/index.html: * DiscImageChef.Settings/Properties/AssemblyInfo.cs: * DiscImageChef.Settings/DiscImageChef.Settings.csproj: * DiscImageChef.Settings/docs/mono/ns-Claunia.PropertyList.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/UID.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/UID.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSSet.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/index.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSSet.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSDate.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSData.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSDate.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSData.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSArray.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSNumber.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSString.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSObject.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSArray.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSNumber.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSString.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSObject.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/NSDictionary.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/NSDictionary.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/PropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/PropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/XmlPropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/XmlPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/ASCIIPropertyListParser.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/ASCIIPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/BinaryPropertyListParser.xml: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/BinaryPropertyListWriter.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/BinaryPropertyListWriter.html: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/BinaryPropertyListParser.html: * DiscImageChef.Settings/docs/mono/Claunia.PropertyList/PropertyListFormatException.xml: * DiscImageChef.Settings/docs/html/Claunia.PropertyList/PropertyListFormatException.html: Added supports for settings * DiscImageChef/Commands/Configure.cs: Added support for settings. * DiscImageChef/Core/Statistics.cs: * DiscImageChef/Commands/Verify.cs: * DiscImageChef/Commands/Entropy.cs: * DiscImageChef/Commands/Formats.cs: * DiscImageChef/Commands/PrintHex.cs: * DiscImageChef/Commands/MediaInfo.cs: * DiscImageChef/Commands/Statistics.cs: Added statistics. * DiscImageChef.Decoders/SCSI/Inquiry.cs: Corrected bug on inquiry decoding. * DiscImageChef.Decoders/SCSI/Modes.cs: Corrected bug on decoding mode page 2Ah without write performance descriptors. Corrected bug when there is a vendor page 0 in mode sense decoding. * DiscImageChef.Devices/Device/Constructor.cs: Corrected detecting USB or FireWire attached CD/DVD/BD and tape drives. Try ATA identify on USB or FireWire that don't have SCSI INQUIRY. * DiscImageChef.DiscImages/CDRWin.cs: Corrected CD-ROM XA vs CD-ROM detection. * DiscImageChef.Partitions/AppleMap.cs: Corrected big endian working. Added debug output. * DiscImageChef.sln: Added supports for settings. * DiscImageChef/Commands/Decode.cs: * DiscImageChef/Commands/Analyze.cs: * DiscImageChef/Commands/Compare.cs: * DiscImageChef/Commands/Checksum.cs: * DiscImageChef/Commands/Benchmark.cs: * DiscImageChef/Commands/DeviceInfo.cs: * DiscImageChef/Commands/CreateSidecar.cs: Added statistics. * DiscImageChef/Commands/DeviceReport.cs: Added statistics. Correct handling empty inquiry string fields. Suppose it is not removable, til proved wrong. Corrected MODE SENSE (6/10) detection and calling order. If device is MMC type but reports neither mode page 2Ah neither GET CONFIGURATION, try all CDs (old drives work like that). Try reading Lead-In and Lead-Out in Audio CD using Audio READ CD commands. Corrected READ LONG information handling, some drives return 2s-complement in 32 bit. Upper 16 bits are ignored. Added support for DVD raw block (37856 bytes). Check READ LONG up to 36 times the cooked block size. That should be enough to detect huge blocked media (like DVD and BD) without taking ages. If READ LONG size had to be bruteforced, and debug is activated, save the result. * DiscImageChef/Commands/DumpMedia.cs: Added statistics. Corrected READ LONG information handling, some drives return 2s-complement in 32 bit. Upper 16 bits are ignored. Start trying with 64 blocks at a time. Some drives report to be able to read 255 at a time, but they really don't, they take a lot longer to read. * DiscImageChef/Commands/MediaScan.cs: Added statistics. Start trying with 64 blocks at a time. Some drives report to be able to read 255 at a time, but they really don't, they take a lot longer to read. * DiscImageChef/DiscImageChef.csproj: Added support for settings. Added statistics. * DiscImageChef/Main.cs: * DiscImageChef/Options.cs: Added support for settings. Added statistics.
2016-02-03 18:58:11 +00:00
return decoded;
Array.Copy(modeResponse, offset, pg.PageResponse, 0, pg.PageResponse.Length);
pg.Page = (byte)(modeResponse[offset] & 0x3F);
pg.Subpage = 0;
offset += pg.PageResponse.Length;
}
2015-10-31 19:41:58 +00:00
}
listpages.Add(pg);
}
decoded.Pages = listpages.ToArray();
return decoded;
}
#region Fujitsu Mode Page 0x3E: Verify Control page
public enum Fujitsu_VerifyModes : byte
{
/// <summary>
/// Always verify after writing
/// </summary>
Always = 0,
/// <summary>
/// Never verify after writing
/// </summary>
Never = 1,
/// <summary>
/// Verify after writing depending on condition
/// </summary>
Depends = 2,
Reserved = 4
}
public struct Fujitsu_ModePage_3E
{
/// <summary>
/// Parameters can be saved
/// </summary>
public bool PS;
/// <summary>
/// If set, AV data support mode is applied
/// </summary>
public bool audioVisualMode;
/// <summary>
/// If set the test write operation is restricted
/// </summary>
public bool streamingMode;
public byte Reserved1;
/// <summary>
/// Verify mode for WRITE commands
/// </summary>
public Fujitsu_VerifyModes verifyMode;
public byte Reserved2;
/// <summary>
/// Device type provided in response to INQUIRY
/// </summary>
public PeripheralDeviceTypes devType;
public byte[] Reserved3;
}
public static Fujitsu_ModePage_3E? DecodeFujitsuModePage_3E(byte[] pageResponse)
{
2016-04-19 02:11:47 +01:00
if(pageResponse == null)
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x40) == 0x40)
return null;
2016-04-19 02:11:47 +01:00
if((pageResponse[0] & 0x3F) != 0x3E)
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
2016-04-19 02:11:47 +01:00
if(pageResponse.Length != 8)
return null;
Fujitsu_ModePage_3E decoded = new Fujitsu_ModePage_3E();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.audioVisualMode |= (pageResponse[2] & 0x80) == 0x80;
decoded.streamingMode |= (pageResponse[2] & 0x40) == 0x40;
decoded.Reserved1 = (byte)((pageResponse[2] & 0x3C) >> 2);
decoded.verifyMode = (Fujitsu_VerifyModes)(pageResponse[2] & 0x03);
decoded.Reserved2 = (byte)((pageResponse[3] & 0xE0) >> 5);
decoded.devType = (PeripheralDeviceTypes)(pageResponse[3] & 0x1F);
decoded.Reserved3 = new byte[4];
Array.Copy(pageResponse, 4, decoded.Reserved3, 0, 4);
return decoded;
}
public static string PrettifyFujitsuModePage_3E(byte[] pageResponse)
{
return PrettifyFujitsuModePage_3E(DecodeFujitsuModePage_3E(pageResponse));
}
public static string PrettifyFujitsuModePage_3E(Fujitsu_ModePage_3E? modePage)
{
2016-04-19 02:11:47 +01:00
if(!modePage.HasValue)
return null;
Fujitsu_ModePage_3E page = modePage.Value;
StringBuilder sb = new StringBuilder();
sb.AppendLine("Fujitsu Verify Control Page:");
2016-04-19 02:11:47 +01:00
if(page.PS)
sb.AppendLine("\tParameters can be saved");
2016-04-19 02:11:47 +01:00
if(page.audioVisualMode)
sb.AppendLine("\tAudio/Visual data support mode is applied");
2016-04-19 02:11:47 +01:00
if(page.streamingMode)
sb.AppendLine("\tTest write operation is restricted during read or write operations.");
2016-04-19 02:11:47 +01:00
switch(page.verifyMode)
{
case Fujitsu_VerifyModes.Always:
sb.AppendLine("\tAlways apply the verify operation");
break;
case Fujitsu_VerifyModes.Never:
sb.AppendLine("\tNever apply the verify operation");
break;
case Fujitsu_VerifyModes.Depends:
sb.AppendLine("\tApply the verify operation depending on the condition");
break;
}
sb.AppendFormat("\tThe device type that would be provided in the INQUIRY response is {0}",
page.devType).AppendLine();
return sb.ToString();
}
#endregion Fujitsu Mode Page 0x3E: Verify Control page
2015-10-24 06:58:49 +01:00
}
}