diff --git a/ChangeLog b/ChangeLog index 3055b29..2d6ebb1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2015-10-30 Natalia Portillo + + * SCSI/Modes.cs: + Added information from SPC-5. + 2015-10-30 Natalia Portillo * SCSI/Modes.cs: diff --git a/SCSI/Modes.cs b/SCSI/Modes.cs index 908cfa6..d54b50c 100644 --- a/SCSI/Modes.cs +++ b/SCSI/Modes.cs @@ -1146,7 +1146,7 @@ namespace DiscImageChef.Decoders.SCSI /// Control mode page /// Page code 0x0A /// 8 bytes in SCSI-2 - /// 12 bytes in SPC-1, SPC-2, SPC-3 + /// 12 bytes in SPC-1, SPC-2, SPC-3, SPC-4, SPC-5 /// public struct ModePage_0A { @@ -1480,7 +1480,7 @@ namespace DiscImageChef.Decoders.SCSI /// /// Disconnect-reconnect page /// Page code 0x02 - /// 16 bytes in SCSI-2, SPC-1, SPC-2, SPC-3 + /// 16 bytes in SCSI-2, SPC-1, SPC-2, SPC-3, SPC-4, SPC-5 /// public struct ModePage_02 { @@ -4048,7 +4048,7 @@ namespace DiscImageChef.Decoders.SCSI /// /// Informational exceptions control page /// Page code 0x1C - /// 12 bytes in SPC-1, SPC-2, SPC-3 + /// 12 bytes in SPC-1, SPC-2, SPC-3, SPC-4 /// public struct ModePage_1C { @@ -4093,6 +4093,11 @@ namespace DiscImageChef.Decoders.SCSI /// Warning reporting enabled /// public bool EWasc; + + /// + /// Enable reporting of background self-test errors + /// + public bool EBACKERR; } public static ModePage_1C? DecodeModePage_1C(byte[] pageResponse) @@ -4117,9 +4122,9 @@ namespace DiscImageChef.Decoders.SCSI decoded.PS |= (pageResponse[0] & 0x80) == 0x80; decoded.Perf |= (pageResponse[2] & 0x80) == 0x80; - decoded.DExcpt |= (pageResponse[2] & 0x80) == 0x80; - decoded.Test |= (pageResponse[2] & 0x80) == 0x80; - decoded.LogErr |= (pageResponse[2] & 0x80) == 0x80; + decoded.DExcpt |= (pageResponse[2] & 0x08) == 0x08; + decoded.Test |= (pageResponse[2] & 0x04) == 0x04; + decoded.LogErr |= (pageResponse[2] & 0x01) == 0x01; decoded.MRIE = (byte)(pageResponse[3] & 0x0F); @@ -4129,6 +4134,8 @@ namespace DiscImageChef.Decoders.SCSI decoded.EBF |= (pageResponse[2] & 0x20) == 0x20; decoded.EWasc |= (pageResponse[2] & 0x10) == 0x10; + decoded.EBACKERR |= (pageResponse[2] & 0x02) == 0x02; + return decoded; } @@ -4207,6 +4214,8 @@ namespace DiscImageChef.Decoders.SCSI sb.AppendLine("\tWarning reporting is enabled"); if (page.EBF) sb.AppendLine("\tBackground functions are enabled"); + if (page.EBACKERR) + sb.AppendLine("\tDrive will report background self-test errors"); return sb.ToString(); } @@ -4216,7 +4225,8 @@ namespace DiscImageChef.Decoders.SCSI /// /// Power condition page /// Page code 0x1A - /// 12 bytes in SPC-1, SPC-2, SPC-3 + /// 12 bytes in SPC-1, SPC-2, SPC-3, SPC-4 + /// 40 bytes in SPC-5 /// public struct ModePage_1A { @@ -4240,6 +4250,38 @@ namespace DiscImageChef.Decoders.SCSI /// Standby timer /// public uint StandbyTimer; + + /// + /// Interactions between background functions and power management + /// + public byte PM_BG_Precedence; + /// + /// Standby timer Y activated + /// + public bool Standby_Y; + /// + /// Idle timer B activated + /// + public bool Idle_B; + /// + /// Idle timer C activated + /// + public bool Idle_C; + /// + /// Idle timer B + /// + public uint IdleTimer_B; + /// + /// Idle timer C + /// + public uint IdleTimer_C; + /// + /// Standby timer Y + /// + public uint StandbyTimer_Y; + public byte CCF_Idle; + public byte CCF_Standby; + public byte CCF_Stopped; } public static ModePage_1A? DecodeModePage_1A(byte[] pageResponse) @@ -4269,6 +4311,22 @@ namespace DiscImageChef.Decoders.SCSI 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]); + if (pageResponse.Length < 40) + 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); + return decoded; } @@ -4290,16 +4348,43 @@ namespace DiscImageChef.Decoders.SCSI if (page.PS) sb.AppendLine("\tParameters can be saved"); - if (page.Standby && page.StandbyTimer > 0) - sb.AppendFormat("\tDrive will enter standby mode in {0} ms", page.StandbyTimer).AppendLine(); + if ((page.Standby && page.StandbyTimer > 0) || + (page.Standby_Y && page.StandbyTimer_Y > 0)) + { + if(page.Standby && page.StandbyTimer > 0) + sb.AppendFormat("\tStandby timer Z is set to {0} ms", page.StandbyTimer * 100).AppendLine(); + if(page.Standby_Y && page.StandbyTimer_Y > 0) + sb.AppendFormat("\tStandby timer Y is set to {0} ms", page.StandbyTimer_Y * 100).AppendLine(); + } else sb.AppendLine("\tDrive will not enter standy mode"); - if(page.Idle && page.IdleTimer > 0) - sb.AppendFormat("\tDrive will enter idle mode in {0} ms", page.StandbyTimer).AppendLine(); + if ((page.Idle && page.IdleTimer > 0) || + (page.Idle_B && page.IdleTimer_B > 0) || + (page.Idle_C && page.IdleTimer_C > 0)) + { + if(page.Idle && page.IdleTimer > 0) + sb.AppendFormat("\tIdle timer A is set to {0} ms", page.IdleTimer * 100).AppendLine(); + if(page.Idle_B && page.IdleTimer_B > 0) + sb.AppendFormat("\tIdle timer B is set to {0} ms", page.IdleTimer_B * 100).AppendLine(); + if(page.Idle_C && page.IdleTimer_C > 0) + sb.AppendFormat("\tIdle timer C is set to {0} ms", page.IdleTimer_C * 100).AppendLine(); + } else sb.AppendLine("\tDrive will not enter idle mode"); + switch (page.PM_BG_Precedence) + { + 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; + } + return sb.ToString(); } #endregion Mode Page 0x1A: Power condition page @@ -4309,7 +4394,7 @@ namespace DiscImageChef.Decoders.SCSI /// Control Extension mode page /// Page code 0x0A /// Subpage code 0x01 - /// 32 bytes in SPC-3 + /// 32 bytes in SPC-3, SPC-4, SPC-5 /// public struct ModePage_0A_S01 { @@ -4333,6 +4418,15 @@ namespace DiscImageChef.Decoders.SCSI /// Initial task priority /// public byte InitialPriority; + + /// + /// Device life control disabled + /// + public bool DLC; + /// + /// Maximum size of SENSE data in bytes + /// + public byte MaximumSenseLength; } public static ModePage_0A_S01? DecodeModePage_0A_S01(byte[] pageResponse) @@ -4399,7 +4493,13 @@ namespace DiscImageChef.Decoders.SCSI if (page.IALUAE) sb.AppendLine("\tImplicit Asymmetric Logical Unit Access is enabled"); - sb.AppendFormat("\tInitial priority is {0}", page.InitialPriority); + sb.AppendFormat("\tInitial priority is {0}", page.InitialPriority).AppendLine(); + + if (page.DLC) + sb.AppendLine("\tDevice will not degrade performance to extend its life"); + + if (page.MaximumSenseLength > 0) + sb.AppendFormat("\tMaximum sense data would be {0} bytes", page.MaximumSenseLength).AppendLine(); return sb.ToString(); }