diff --git a/DiscImageChef.Decoders/ChangeLog b/DiscImageChef.Decoders/ChangeLog index fac95857..0f04dbde 100644 --- a/DiscImageChef.Decoders/ChangeLog +++ b/DiscImageChef.Decoders/ChangeLog @@ -1,3 +1,8 @@ +2016-10-13 Natalia Portillo + + * Modes.cs: Added support for SCSI MODE PAGEs 11h, 12h, 13h + and 14h (medium partitions) + 2016-10-10 Natalia Portillo * Modes.cs: Added DDS-2. diff --git a/DiscImageChef.Decoders/SCSI/Modes.cs b/DiscImageChef.Decoders/SCSI/Modes.cs index 38b2cb65..13d22b83 100644 --- a/DiscImageChef.Decoders/SCSI/Modes.cs +++ b/DiscImageChef.Decoders/SCSI/Modes.cs @@ -6771,6 +6771,323 @@ namespace DiscImageChef.Decoders.SCSI } #endregion Fujitsu Mode Page 0x3E: Verify Control page + + #region Mode Page 0x11: Medium partition page (1) + + public enum PartitionSizeUnitOfMeasures : byte + { + /// + /// Partition size is measures in bytes + /// + Bytes = 0, + /// + /// Partition size is measures in Kilobytes + /// + Kilobytes = 1, + /// + /// Partition size is measures in Megabytes + /// + Megabytes = 2, + /// + /// Partition size is 10eUNITS bytes + /// + Exponential = 3 + } + + public enum MediumFormatRecognitionValues : byte + { + /// + /// Logical unit is incapable of format or partition recognition + /// + Incapable = 0, + /// + /// Logical unit is capable of format recognition only + /// + FormatCapable = 1, + /// + /// Logical unit is capable of partition recognition only + /// + PartitionCapable = 2, + /// + /// Logical unit is capable of both format and partition recognition + /// + Capable = 3 + } + + /// + /// Medium partition page(1) + /// Page code 0x11 + /// + public struct ModePage_11 + { + /// + /// Parameters can be saved + /// + public bool PS; + /// + /// Maximum number of additional partitions supported + /// + public byte MaxAdditionalPartitions; + /// + /// Number of additional partitions to be defined for a volume + /// + public byte AdditionalPartitionsDefined; + /// + /// Device defines partitions based on its fixed definition + /// + public bool FDP; + /// + /// Device should divide medium according to the additional partitions defined field using sizes defined by device + /// + public bool SDP; + /// + /// Initiator defines number and size of partitions + /// + public bool IDP; + /// + /// Defines the unit on which the partition sizes are defined + /// + public PartitionSizeUnitOfMeasures PSUM; + public bool POFM; + public bool CLEAR; + public bool ADDP; + /// + /// Defines the capabilities for the unit to recognize media partitions and format + /// + public MediumFormatRecognitionValues MediumFormatRecognition; + public byte PartitionUnits; + /// + /// Array of partition sizes in units defined above + /// + public ushort[] PartitionSizes; + } + + public static ModePage_11? DecodeModePage_11(byte[] pageResponse) + { + if(pageResponse == null) + return null; + + if((pageResponse[0] & 0x40) == 0x40) + return null; + + if((pageResponse[0] & 0x3F) != 0x11) + return null; + + if(pageResponse[1] + 2 != pageResponse.Length) + return null; + + if(pageResponse.Length < 8) + return null; + + ModePage_11 decoded = new ModePage_11(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + + decoded.MaxAdditionalPartitions = pageResponse[2]; + decoded.AdditionalPartitionsDefined = pageResponse[3]; + decoded.FDP |= (pageResponse[4] & 0x80) == 0x80; + decoded.SDP |= (pageResponse[4] & 0x40) == 0x40; + decoded.IDP |= (pageResponse[4] & 0x20) == 0x20; + decoded.PSUM = (PartitionSizeUnitOfMeasures)((pageResponse[4] & 0x18) >> 3); + decoded.POFM |= (pageResponse[4] & 0x04) == 0x04; + decoded.CLEAR |= (pageResponse[4] & 0x02) == 0x02; + decoded.ADDP |= (pageResponse[4] & 0x01) == 0x01; + decoded.PartitionUnits = (byte)(pageResponse[6] & 0x0F); + decoded.MediumFormatRecognition = (MediumFormatRecognitionValues)pageResponse[5]; + decoded.PartitionSizes = new ushort[(pageResponse.Length - 8) / 2]; + + for(int i = 8; i < pageResponse.Length; i+=2) + { + decoded.PartitionSizes[(i - 8) / 2] = (ushort)(pageResponse[i] << 8); + decoded.PartitionSizes[(i - 8) / 2] += pageResponse[i+1]; + } + + return decoded; + } + + public static string PrettifyModePage_11(byte[] pageResponse) + { + return PrettifyModePage_11(DecodeModePage_11(pageResponse)); + } + + public static string PrettifyModePage_11(ModePage_11? modePage) + { + if(!modePage.HasValue) + return null; + + ModePage_11 page = modePage.Value; + StringBuilder sb = new StringBuilder(); + + sb.AppendLine("SCSI medium partition page:"); + + if(page.PS) + sb.AppendLine("\tParameters can be saved"); + + sb.AppendFormat("\t{0} maximum additional partitions", page.MaxAdditionalPartitions).AppendLine(); + sb.AppendFormat("\t{0} additional partitions defined", page.AdditionalPartitionsDefined).AppendLine(); + + if(page.FDP) + sb.AppendLine("\tPartitions are fixed under device definitions"); + if(page.SDP) + sb.AppendLine("\tNumber of partitions can be defined but their size is defined by the device"); + if(page.IDP) + sb.AppendLine("\tNumber and size of partitions can be manually defined"); + if(page.POFM) + sb.AppendLine("\tPartition parameters will not be applied until a FORMAT MEDIUM command is received"); + if(!page.CLEAR && !page.ADDP) + sb.AppendLine("\tDevice may erase any or all partitions on MODE SELECT for partitioning"); + else if(page.CLEAR && !page.ADDP) + sb.AppendLine("\tDevice shall erase all partitions on MODE SELECT for partitioning"); + else if(!page.CLEAR && page.ADDP) + sb.AppendLine("\tDevice shall not erase any partition on MODE SELECT for partitioning"); + else if(page.CLEAR && page.ADDP) + sb.AppendLine("\tDevice shall erase all partitions differing on size on MODE SELECT for partitioning"); + + string measure = ""; + + switch(page.PSUM) + { + case PartitionSizeUnitOfMeasures.Bytes: + sb.AppendLine("\tPartitions are defined in bytes"); + measure = "bytes"; + break; + case PartitionSizeUnitOfMeasures.Kilobytes: + sb.AppendLine("\tPartitions are defined in kilobytes"); + measure = "kilobytes"; + break; + case PartitionSizeUnitOfMeasures.Megabytes: + sb.AppendLine("\tPartitions are defined in megabytes"); + measure = "megabytes"; + break; + case PartitionSizeUnitOfMeasures.Exponential: + sb.AppendFormat("\tPartitions are defined in units of {0} bytes", Math.Pow(10, page.PartitionUnits)).AppendLine(); + measure = string.Format("units of {0} bytes", Math.Pow(10, page.PartitionUnits)); + break; + default: + sb.AppendFormat("\tUnknown partition size unit code {0}", (byte)page.PSUM).AppendLine(); + measure = "units"; + break; + } + + switch(page.MediumFormatRecognition) + { + case MediumFormatRecognitionValues.Capable: + sb.AppendLine("\tDevice is capable of recognizing both medium partitions and format"); + break; + case MediumFormatRecognitionValues.FormatCapable: + sb.AppendLine("\tDevice is capable of recognizing medium format"); + break; + case MediumFormatRecognitionValues.PartitionCapable: + sb.AppendLine("\tDevice is capable of recognizing medium partitions"); + break; + case MediumFormatRecognitionValues.Incapable: + sb.AppendLine("\tDevice is not capable of recognizing neither medium partitions nor format"); + break; + default: + sb.AppendFormat("\tUnknown medium recognition code {0}", (byte)page.MediumFormatRecognition).AppendLine(); + break; + } + + sb.AppendFormat("\tMedium has defined {0} partitions", page.PartitionSizes.Length).AppendLine(); + + for(int i = 0; i < page.PartitionSizes.Length; i++) + { + if(page.PartitionSizes[i] == 0) + { + if(page.PartitionSizes.Length == 1) + sb.AppendLine("\tDevice recognizes one single partition spanning whole medium"); + else + sb.AppendFormat("\tPartition {0} runs for rest of medium", i).AppendLine(); + } + else + sb.AppendFormat("\tPartition {0} is {1} {2} long", i, page.PartitionSizes[i], measure).AppendLine(); + } + + return sb.ToString(); + } + + #endregion Mode Page 0x11: Medium partition page (1) + + #region Mode Pages 0x12, 0x13, 0x14: Medium partition page (2-4) + + /// + /// Medium partition page (2-4) + /// Page codes 0x12, 0x13 and 0x14 + /// + public struct ModePage_12_13_14 + { + /// + /// Parameters can be saved + /// + public bool PS; + /// + /// Array of partition sizes in units defined in mode page 11 + /// + public ushort[] PartitionSizes; + } + + public static ModePage_12_13_14? DecodeModePage_12_13_14(byte[] pageResponse) + { + if(pageResponse == null) + return null; + + if((pageResponse[0] & 0x40) == 0x40) + return null; + + if((pageResponse[0] & 0x3F) != 0x12 && + (pageResponse[0] & 0x3F) != 0x13 && + (pageResponse[0] & 0x3F) != 0x14) + return null; + + if(pageResponse[1] + 2 != pageResponse.Length) + return null; + + if(pageResponse.Length < 2) + return null; + + ModePage_12_13_14 decoded = new ModePage_12_13_14(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + + decoded.PartitionSizes = new ushort[(pageResponse.Length - 2) / 2]; + + for(int i = 2; i < pageResponse.Length; i += 2) + { + decoded.PartitionSizes[(i - 2) / 2] = (ushort)(pageResponse[i] << 8); + decoded.PartitionSizes[(i - 2) / 2] += pageResponse[i + 1]; + } + + return decoded; + } + + public static string PrettifyModePage_12_13_14(byte[] pageResponse) + { + return PrettifyModePage_12_13_14(DecodeModePage_12_13_14(pageResponse)); + } + + public static string PrettifyModePage_12_13_14(ModePage_12_13_14? modePage) + { + if(!modePage.HasValue) + return null; + + ModePage_12_13_14 page = modePage.Value; + StringBuilder sb = new StringBuilder(); + + sb.AppendLine("SCSI medium partition page (extra):"); + + if(page.PS) + sb.AppendLine("\tParameters can be saved"); + + sb.AppendFormat("\tMedium has defined {0} partitions", page.PartitionSizes.Length).AppendLine(); + + for(int i = 0; i < page.PartitionSizes.Length; i++) + sb.AppendFormat("\tPartition {0} is {1} units long", i, page.PartitionSizes[i]).AppendLine(); + + return sb.ToString(); + } + + #endregion Mode Pages 0x12, 0x13, 0x14: Medium partition page (2-4) + } } diff --git a/DiscImageChef/ChangeLog b/DiscImageChef/ChangeLog index 44ca9602..9361cc09 100644 --- a/DiscImageChef/ChangeLog +++ b/DiscImageChef/ChangeLog @@ -1,3 +1,9 @@ +2016-10-13 Natalia Portillo + + * Commands/DeviceInfo.cs: + Added support for SCSI MODE PAGEs 11h, 12h, 13h and 14h + (medium partitions) + 2016-10-12 Natalia Portillo * Commands/DumpMedia.cs: diff --git a/DiscImageChef/Commands/DeviceInfo.cs b/DiscImageChef/Commands/DeviceInfo.cs index 84c6938b..731a2911 100644 --- a/DiscImageChef/Commands/DeviceInfo.cs +++ b/DiscImageChef/Commands/DeviceInfo.cs @@ -464,6 +464,26 @@ namespace DiscImageChef.Commands else goto default; + break; + } + case 0x11: + { + if(page.Subpage == 0) + DicConsole.WriteLine(Decoders.SCSI.Modes.PrettifyModePage_11(page.PageResponse)); + else + goto default; + + break; + } + case 0x12: + case 0x13: + case 0x14: + { + if(page.Subpage == 0) + DicConsole.WriteLine(Decoders.SCSI.Modes.PrettifyModePage_12_13_14(page.PageResponse)); + else + goto default; + break; } case 0x1A: