From 95c25def4aff35acd1bce46cf5bef6c23724b204 Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Sat, 24 Oct 2015 06:58:49 +0100 Subject: [PATCH] Implement SCSI-1 Mode Page decoding. --- ChangeLog | 6 + DiscImageChef.Decoders.csproj | 1 + SCSI/Modes.cs | 382 ++++++++++++++++++++++++++++++++++ 3 files changed, 389 insertions(+) create mode 100644 SCSI/Modes.cs diff --git a/ChangeLog b/ChangeLog index c867e19d8..5d3410103 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2015-10-24 Natalia Portillo + + * SCSI/Modes.cs: + * DiscImageChef.Decoders.csproj: + Implement SCSI-1 Mode Page decoding. + 2015-10-23 Natalia Portillo * SCSI/Enums.cs: diff --git a/DiscImageChef.Decoders.csproj b/DiscImageChef.Decoders.csproj index 3dda09b58..3d6b4c348 100644 --- a/DiscImageChef.Decoders.csproj +++ b/DiscImageChef.Decoders.csproj @@ -79,6 +79,7 @@ + diff --git a/SCSI/Modes.cs b/SCSI/Modes.cs new file mode 100644 index 000000000..6591e872b --- /dev/null +++ b/SCSI/Modes.cs @@ -0,0 +1,382 @@ +// /*************************************************************************** +// 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 . +// +// ---------------------------------------------------------------------------- +// Copyright (C) 2011-2015 Claunia.com +// ****************************************************************************/ +// //$Id$ +using System; +using System.Text; + +namespace DiscImageChef.Decoders.SCSI +{ + public static class Modes + { + public enum MediumTypes : byte + { + Default = 0x00, + #region Medium Types defined in ECMA-111 for Direct-Access devices + /// + /// ECMA-54: 200 mm Flexible Disk Cartridge using Two-Frequency Recording at 13262 ftprad on One Side + /// + ECMA54 = 0x09, + /// + /// ECMA-59: 200 mm Flexible Disk Cartridge using Two-Frequency Recording at 13262 ftprad on Both Sides + /// + ECMA59 = 0x0A, + /// + /// ECMA-69: 200 mm Flexible Disk Cartridge using MFM Recording at 13262 ftprad on Both Sides + /// + ECMA69 = 0x0B, + /// + /// ECMA-66: 130 mm Flexible Disk Cartridge using Two-Frequency Recording at 7958 ftprad on One Side + /// + ECMA66 = 0x0E, + /// + /// ECMA-70: 130 mm Flexible Disk Cartridge using MFM Recording at 7958 ftprad on Both Sides; 1,9 Tracks per mm + /// + ECMA70 = 0x12, + /// + /// ECMA-78: 130 mm Flexible Disk Cartridge using MFM Recording at 7958 ftprad on Both Sides; 3,8 Tracks per mm + /// + ECMA78 = 0x16, + /// + /// ECMA-99: 130 mm Flexible Disk Cartridge using MFM Recording at 13262 ftprad on Both Sides; 3,8 Tracks per mm + /// + ECMA99 = 0x1A, + /// + /// ECMA-100: 90 mm Flexible Disk Cartridge using MFM Recording at 7859 ftprad on Both Sides; 5,3 Tracks per mm + /// + ECMA100 = 0x1E + #endregion Medium Types defined in ECMA-111 for Direct-Access devices + } + + public enum DensityType : byte + { + Default = 0x00, + #region Density Types defined in ECMA-111 for Direct-Access devices + /// + /// 7958 flux transitions per radian + /// + Flux7958 = 0x01, + /// + /// 13262 flux transitions per radian + /// + Flux13262 = 0x02, + /// + /// 15916 flux transitions per radian + /// + Flux15916 = 0x03, + #endregion Density Types defined in ECMA-111 for Direct-Access devices + + #region Medium Types defined in ECMA-111 for Sequential-Access devices + /// + /// ECMA-62: 12,7 mm 9-Track Magnetic Tape, 32 ftpmm, NRZ1, 32 cpmm + /// + ECMA62 = 0x01, + /// + /// ECMA-62: 12,7 mm 9-Track Magnetic Tape, 126 ftpmm, Phase Encoding, 63 cpmm + /// + ECMA62_Phase = 0x02, + /// + /// ECMA-62: 12,7 mm 9-Track Magnetic Tape, 356 ftpmm, NRZ1, 245 cpmm GCR + /// + ECMA62_GCR = 0x03, + /// + /// ECMA-79: 6,30 mm Magnetic Tape Cartridge using MFM Recording at 252 ftpmm + /// + ECMA79 = 0x07, + /// + /// Draft ECMA: 12,7 mm Magnetic Tape Cartridge using IFM Recording on 18 Tracks at 1944 ftpmm, GCR + /// + ECMADraft = 0x09, + /// + /// ECMA-46: 6,30 mm Magnetic Tape Cartridge, Phase Encoding, 63 bpmm + /// + ECMA46 = 0x0B, + /// + /// ECMA-98: 6,30 mm Magnetic Tape Cartridge, NRZ1 Recording, 394 ftpmm + /// + ECMA98 = 0x0E + #endregion Medium Types defined in ECMA-111 for Sequential-Access devices + } + + public struct BlockDescriptor + { + public DensityType Density; + public ulong Blocks; + public ulong BlockLength; + } + + public struct ModeHeader + { + public MediumTypes MediumType; + public bool WriteProtected; + public BlockDescriptor[] BlockDescriptors; + public byte Speed; + public byte BufferedMode; + public bool EBC; + } + + public static ModeHeader? DecodeModeHeader6(byte[] modeResponse, PeripheralDeviceTypes deviceType) + { + if (modeResponse.Length < modeResponse[0] + 1) + return null; + + ModeHeader header = new ModeHeader(); + header.MediumType = (MediumTypes)modeResponse[1]; + + if (modeResponse[3] > 0) + { + header.BlockDescriptors = new BlockDescriptor[modeResponse[3]/8]; + for (int i = 0; i < header.BlockDescriptors.Length; i++) + { + 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]; + header.BlockDescriptors[i].BlockLength += (ulong)(modeResponse[5 + i * 8 + 4] << 16); + header.BlockDescriptors[i].BlockLength += (ulong)(modeResponse[6 + i * 8 + 4] << 8); + header.BlockDescriptors[i].BlockLength += modeResponse[7 + i * 8 + 4]; + } + } + + if (deviceType == PeripheralDeviceTypes.DirectAccess) + header.WriteProtected = ((modeResponse[2] & 0x80) == 0x80); + + if (deviceType == PeripheralDeviceTypes.SequentialAccess) + { + header.WriteProtected = ((modeResponse[2] & 0x80) == 0x80); + header.Speed = (byte)(modeResponse[2] & 0x0F); + header.BufferedMode = (byte)((modeResponse[2] & 0x70) >> 4); + } + + if (deviceType == PeripheralDeviceTypes.PrinterDevice) + header.BufferedMode = (byte)((modeResponse[2] & 0x70) >> 4); + + if (deviceType == PeripheralDeviceTypes.OpticalDevice) + { + header.WriteProtected = ((modeResponse[2] & 0x80) == 0x80); + header.EBC = ((modeResponse[2] & 0x01) == 0x01); + } + + return header; + } + + public static string PrettifyModeHeader6(byte[] modeResponse, PeripheralDeviceTypes deviceType) + { + return PrettifyModeHeader(DecodeModeHeader6(modeResponse, deviceType), deviceType); + } + + public static string PrettifyModeHeader(ModeHeader? header, PeripheralDeviceTypes deviceType) + { + if (!header.HasValue) + return null; + + StringBuilder sb = new StringBuilder(); + + sb.AppendLine("SCSI Mode Page 0:"); + + switch (deviceType) + { + case PeripheralDeviceTypes.DirectAccess: + { + sb.Append("Medium is "); + + switch (header.Value.MediumType) + { + 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: 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: 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: 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: 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: 90 mm Flexible Disk Cartridge using MFM Recording at 7859 ftprad on Both Sides; 5,3 Tracks per mm"); + break; + default: + sb.AppendFormat("Unknown medium type 0x{0:X2}", header.Value.MediumType).AppendLine(); + break; + } + + if (header.Value.WriteProtected) + sb.AppendLine("Medium is write protected"); + + foreach (BlockDescriptor descriptor in header.Value.BlockDescriptors) + { + string density; + switch (descriptor.Density) + { + 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}", descriptor.Density); + break; + } + + if (descriptor.Blocks == 0) + sb.AppendFormat("All remaining blocks have {0} and are {1} bytes each", density, descriptor.BlockLength).AppendLine(); + else + sb.AppendFormat("{0} blocks have {1} and are {2} bytes each", descriptor.Blocks, density, descriptor.BlockLength).AppendLine(); + } + + break; + } + case PeripheralDeviceTypes.SequentialAccess: + { + switch (header.Value.BufferedMode) + { + case 0: + sb.AppendLine("Device writes directly to media"); + break; + case 1: + sb.AppendLine("Device uses a write cache"); + break; + default: + sb.AppendFormat("Unknown buffered mode code 0x{0:X2}", header.Value.BufferedMode).AppendLine(); + break; + } + + if (header.Value.Speed == 0) + sb.AppendLine("Device uses default speed"); + else + sb.AppendFormat("Device uses speed {0}", header.Value.Speed).AppendLine(); + + if (header.Value.WriteProtected) + sb.AppendLine("Medium is write protected"); + + foreach (BlockDescriptor descriptor in header.Value.BlockDescriptors) + { + string density; + switch (descriptor.Density) + { + case DensityType.ECMA62: + density = "ECMA-62: 12,7 mm 9-Track Magnetic Tape, 32 ftpmm, NRZ1, 32 cpmm"; + break; + case DensityType.ECMA62_Phase: + density = "ECMA-62: 12,7 mm 9-Track Magnetic Tape, 126 ftpmm, Phase Encoding, 63 cpmm"; + break; + case DensityType.ECMA62_GCR: + density = "ECMA-62: 12,7 mm 9-Track Magnetic Tape, 356 ftpmm, NRZ1, 245 cpmm GCR"; + break; + case DensityType.ECMA79: + density = "ECMA-79: 6,30 mm Magnetic Tape Cartridge, 252 ftpmm, MFM"; + break; + case DensityType.ECMADraft: + density = "Draft ECMA: 12,7 mm 18-Track Magnetic Tape Cartridge, 1944 ftpmm, IFM, GCR"; + break; + case DensityType.ECMA46: + density = "ECMA-46: 6,30 mm Magnetic Tape Cartridge, Phase Encoding, 63 bpmm"; + break; + case DensityType.ECMA98: + density = "ECMA-98: 6,30 mm Magnetic Tape Cartridge, NRZ1, 394 ftpmm"; + break; + default: + density = String.Format("Unknown density code 0x{0:X2}", descriptor.Density); + break; + } + + if (descriptor.Blocks == 0) + { + if (descriptor.BlockLength == 0) + sb.AppendFormat("All remaining blocks conform to {0} and have a variable length", density).AppendLine(); + else + sb.AppendFormat("All remaining blocks conform to {0} and are {1} bytes each", density, descriptor.BlockLength).AppendLine(); + } + else + { + if (descriptor.BlockLength == 0) + sb.AppendFormat("{0} blocks conform to {1} and have a variable length", descriptor.Blocks, density).AppendLine(); + else + sb.AppendFormat("{0} blocks conform to {1} and are {2} bytes each", descriptor.Blocks, density, descriptor.BlockLength).AppendLine(); + } + } + + break; + } + case PeripheralDeviceTypes.PrinterDevice: + { + switch (header.Value.BufferedMode) + { + case 0: + sb.AppendLine("Device prints directly"); + break; + case 1: + sb.AppendLine("Device uses a print cache"); + break; + default: + sb.AppendFormat("Unknown buffered mode code 0x{0:X2}", header.Value.BufferedMode).AppendLine(); + break; + } + break; + } + case PeripheralDeviceTypes.OpticalDevice: + { + if (header.Value.WriteProtected) + sb.AppendLine("Medium is write protected"); + if (header.Value.EBC) + sb.AppendLine("Blank checking during write is enabled"); + + break; + } + default: + break; + } + + return sb.ToString(); + } + } +} +