diff --git a/ChangeLog b/ChangeLog index b4299a9..bf46f80 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2015-10-30 Natalia Portillo + + * SCSI/Modes.cs: + Implemented decoding mode page 10h. + 2015-10-30 Natalia Portillo * SCSI/Modes.cs: diff --git a/SCSI/Modes.cs b/SCSI/Modes.cs index cc750bd..f4302ac 100644 --- a/SCSI/Modes.cs +++ b/SCSI/Modes.cs @@ -2523,6 +2523,246 @@ namespace DiscImageChef.Decoders.SCSI return sb.ToString(); } #endregion Mode Page 0x07: Verify error recovery page + + #region Mode Page 0x10: Device configuration page + /// + /// Device configuration page + /// Page code 0x10 + /// 16 bytes in SCSI-2 + /// + public struct ModePage_10 + { + /// + /// Parameters can be saved + /// + public bool PS; + /// + /// Used in mode select to change partition to one specified in + /// + public bool CAP; + /// + /// Used in mode select to change format to one specified in + /// + public bool CAF; + /// + /// Active format, vendor-specific + /// + public byte ActiveFormat; + /// + /// Current logical partition + /// + public byte ActivePartition; + /// + /// How full the buffer shall be before writing to medium + /// + public byte WriteBufferFullRatio; + /// + /// How empty the buffer shall be before reading more data from the medium + /// + public byte ReadBufferEmptyRatio; + /// + /// Delay in 100 ms before buffered data is forcefully written to the medium even before buffer is full + /// + public ushort WriteDelayTime; + /// + /// Drive supports recovering data from buffer + /// + public bool DBR; + /// + /// Medium has block IDs + /// + public bool BIS; + /// + /// Drive recognizes and reports setmarks + /// + public bool RSmk; + /// + /// Drive selects best speed + /// + public bool AVC; + /// + /// If drive should stop pre-reading on filemarks + /// + public byte SOCF; + /// + /// If set, recovered buffer data is LIFO, otherwise, FIFO + /// + public bool RBO; + /// + /// Report early warnings + /// + public bool REW; + /// + /// Inter-block gap + /// + public byte GapSize; + /// + /// End-of-Data format + /// + public byte EODDefined; + /// + /// EOD generation enabled + /// + public bool EEG; + /// + /// Synchronize data to medium on early warning + /// + public bool SEW; + /// + /// Bytes to reduce buffer size on early warning + /// + public uint BufferSizeEarlyWarning; + /// + /// Selected data compression algorithm + /// + public byte SelectedCompression; + } + + + public static ModePage_10? DecodeModePage_10(byte[] pageResponse) + { + if (pageResponse == null) + return null; + + if ((pageResponse[0] & 0x3F) != 0x10) + return null; + + if (pageResponse[1] + 2 != pageResponse.Length) + return null; + + if (pageResponse.Length < 16) + return null; + + ModePage_10 decoded = new ModePage_10(); + + 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]; + + return decoded; + } + + public static string PrettifyModePage_10(byte[] pageResponse) + { + return PrettifyModePage_10(DecodeModePage_10(pageResponse)); + } + + public static string PrettifyModePage_10(ModePage_10? modePage) + { + if (!modePage.HasValue) + return null; + + ModePage_10 page = modePage.Value; + StringBuilder sb = new StringBuilder(); + + sb.AppendLine("SCSI Device configuration page:"); + + if (page.PS) + sb.AppendLine("\tParameters can be saved"); + + 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(); + if (page.DBR) + { + sb.AppendLine("\tDrive supports recovering data from buffer"); + if (page.RBO) + sb.AppendLine("\tRecovered buffer data comes in LIFO order"); + else + sb.AppendLine("\tRecovered buffer data comes in FIFO order"); + } + if (page.BIS) + sb.AppendLine("\tMedium supports block IDs"); + if (page.RSmk) + sb.AppendLine("\tDrive reports setmarks"); + switch (page.SOCF) + { + 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; + } + + if (page.REW) + { + sb.AppendLine("\tDrive reports early warnings"); + if (page.SEW) + sb.AppendLine("\tDrive will synchronize buffer to medium on early warnings"); + } + + switch (page.GapSize) + { + 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; + } + + if (page.EEG) + sb.AppendLine("\tDrive generates end-of-data"); + + switch (page.SelectedCompression) + { + 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; + } + + return sb.ToString(); + } + #endregion Mode Page 0x10: Device configuration page } }