diff --git a/DiscImageChef.Decoders/ChangeLog b/DiscImageChef.Decoders/ChangeLog index 4b0a5c5f..5eedb323 100644 --- a/DiscImageChef.Decoders/ChangeLog +++ b/DiscImageChef.Decoders/ChangeLog @@ -1,3 +1,8 @@ +2015-10-25 Natalia Portillo + + * SCSI/Modes.cs: + Implemented decoding mode page 02h. + 2015-10-25 Natalia Portillo * SCSI/Modes.cs: diff --git a/DiscImageChef.Decoders/SCSI/Modes.cs b/DiscImageChef.Decoders/SCSI/Modes.cs index c361f45d..1884e8ba 100644 --- a/DiscImageChef.Decoders/SCSI/Modes.cs +++ b/DiscImageChef.Decoders/SCSI/Modes.cs @@ -1286,7 +1286,155 @@ namespace DiscImageChef.Decoders.SCSI return sb.ToString(); } - #endregion Mode Page 0x0a: Control mode page + #endregion Mode Page 0x0A: Control mode page + + #region Mode Page 0x02: Disconnect-reconnect page + /// + /// Disconnect-reconnect page + /// Page code 0x02 + /// 16 bytes in SCSI-2 + /// + public struct ModePage_02 + { + /// + /// Parameters can be saved + /// + public bool PS; + /// + /// How full should be the buffer prior to attempting a reselection + /// + public byte BufferFullRatio; + /// + /// How empty should be the buffer prior to attempting a reselection + /// + public byte BufferEmptyRatio; + /// + /// Max. time in 100 µs increments that the target is permitted to assert BSY without a REQ/ACK + /// + public ushort BusInactivityLimit; + /// + /// Min. time in 100 µs increments to wait after releasing the bus before attempting reselection + /// + public ushort DisconnectTimeLimit; + /// + /// Max. time in 100 µs increments allowed to use the bus before disconnecting, if granted the privilege and not restricted by + /// + public ushort ConnectTimeLimit; + /// + /// Maximum amount of data before disconnecting in 512 bytes increments + /// + public ushort MaxBurstSize; + /// + /// Data transfer disconnect control + /// + public byte DTDC; + + /// + /// Target shall not transfer data for a command during the same interconnect tenancy + /// + public bool DIMM; + /// + /// Wether to use fair or unfair arbitration when requesting an interconnect tenancy + /// + public byte FairArbitration; + /// + /// Max. ammount of data in 512 bytes increments that may be transferred for a command along with the command + /// + public ushort FirstBurstSize; + /// + /// Target is allowed to re-order the data transfer + /// + public bool EMDP; + } + + public static ModePage_02? DecodeModePage_02(byte[] pageResponse) + { + if (pageResponse == null) + return null; + + if ((pageResponse[0] & 0x3F) != 0x02) + return null; + + if (pageResponse[1] + 2 != pageResponse.Length) + return null; + + if (pageResponse.Length < 16) + 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) + { + if (!modePage.HasValue) + return null; + + ModePage_02 page = modePage.Value; + StringBuilder sb = new StringBuilder(); + + sb.AppendLine("SCSI Disconnect-Reconnect mode page:"); + + if (page.PS) + sb.AppendLine("\tParameters can be saved"); + if (page.BufferFullRatio > 0) + sb.AppendFormat("\t{0} ratio of buffer that shall be full prior to attempting a reselection", page.BufferFullRatio).AppendLine(); + if (page.BufferEmptyRatio > 0) + sb.AppendFormat("\t{0} ratio of buffer that shall be empty prior to attempting a reselection", page.BufferEmptyRatio).AppendLine(); + if (page.BusInactivityLimit > 0) + sb.AppendFormat("\t{0} µs maximum permitted to assert BSY without a REQ/ACK handshake", (int)page.BusInactivityLimit * 100).AppendLine(); + if (page.DisconnectTimeLimit > 0) + sb.AppendFormat("\t{0} µs maximum permitted wait after releasing the bus before attempting reselection", (int)page.DisconnectTimeLimit * 100).AppendLine(); + if (page.ConnectTimeLimit > 0) + sb.AppendFormat("\t{0} µs allowed to use the bus before disconnecting, if granted the privilege and not restricted", (int)page.ConnectTimeLimit * 100).AppendLine(); + if (page.MaxBurstSize > 0) + sb.AppendFormat("\t{0} bytes maximum can be transferred before disconnecting", (int)page.MaxBurstSize * 512).AppendLine(); + if (page.FirstBurstSize > 0) + sb.AppendFormat("\t{0} bytes maximum can be transferred for a command along with the disconnect command", (int)page.FirstBurstSize * 512).AppendLine(); + + if (page.DIMM) + sb.AppendLine("\tTarget shall not transfer data for a command during the same interconnect tenancy"); + if (page.EMDP) + sb.AppendLine("\tTarget is allowed to re-order the data transfer"); + + switch (page.DTDC) + { + 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(); + } + #endregion Mode Page 0x02: Disconnect-reconnect page } }