// /*************************************************************************** // Aaru Data Preservation Suite // ---------------------------------------------------------------------------- // // Filename : 0A.cs // Author(s) : Natalia Portillo // // Component : Device structures decoders. // // --[ Description ] ---------------------------------------------------------- // // Decodes SCSI MODE PAGE 0Ah: Control mode page. // // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as // published by the Free Software Foundation; either version 2.1 of the // License, or (at your option) any later version. // // This library 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 // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, see . // // ---------------------------------------------------------------------------- // Copyright © 2011-2023 Natalia Portillo // ****************************************************************************/ using System.Diagnostics.CodeAnalysis; using System.Text; namespace Aaru.Decoders.SCSI; [SuppressMessage("ReSharper", "InconsistentNaming")] [SuppressMessage("ReSharper", "MemberCanBeInternal")] [SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] public static partial class Modes { #region Mode Page 0x0A: Control mode page /// Control mode page Page code 0x0A 8 bytes in SCSI-2 12 bytes in SPC-1, SPC-2, SPC-3, SPC-4, SPC-5 public struct ModePage_0A { /// Parameters can be saved public bool PS; /// If set, target shall report log exception conditions public bool RLEC; /// Queue algorithm modifier public byte QueueAlgorithm; /// /// If set all remaining suspended I/O processes shall be aborted after the contingent allegiance condition or /// extended contingent allegiance condition /// public byte QErr; /// Tagged queuing is disabled public bool DQue; /// Extended Contingent Allegiance is enabled public bool EECA; /// Target may issue an asynchronous event notification upon completing its initialization public bool RAENP; /// Target may issue an asynchronous event notification instead of a unit attention condition public bool UAAENP; /// Target may issue an asynchronous event notification instead of a deferred error public bool EAENP; /// Minimum time in ms after initialization before attempting asynchronous event notifications public ushort ReadyAENHoldOffPeriod; /// Global logging target save disabled public bool GLTSD; /// CHECK CONDITION should be reported rather than a long busy condition public bool RAC; /// Software write protect is active public bool SWP; /// Maximum time in 100 ms units allowed to remain busy. 0xFFFF == unlimited. public ushort BusyTimeoutPeriod; /// Task set type public byte TST; /// Tasks aborted by other initiator's actions should be terminated with TASK ABORTED public bool TAS; /// Action to be taken when a medium is inserted public byte AutoloadMode; /// Time in seconds to complete an extended self-test public byte ExtendedSelfTestCompletionTime; /// All tasks received in nexus with ACA ACTIVE is set and an ACA condition is established shall terminate public bool TMF_ONLY; /// /// Device shall return descriptor format sense data when returning sense data in the same transactions as a CHECK /// CONDITION /// public bool D_SENSE; /// Unit attention interlocks control public byte UA_INTLCK_CTRL; /// LOGICAL BLOCK APPLICATION TAG should not be modified public bool ATO; /// Protector information checking is disabled public bool DPICZ; /// No unit attention on release public bool NUAR; /// Application Tag mode page is enabled public bool ATMPE; /// Abort any write command without protection information public bool RWWP; /// Supportes block lengths and protection information public bool SBLP; } public static ModePage_0A? DecodeModePage_0A(byte[] pageResponse) { if((pageResponse?[0] & 0x40) == 0x40) return null; if((pageResponse?[0] & 0x3F) != 0x0A) return null; if(pageResponse[1] + 2 != pageResponse.Length) return null; if(pageResponse.Length < 8) return null; var decoded = new ModePage_0A(); decoded.PS |= (pageResponse[0] & 0x80) == 0x80; decoded.RLEC |= (pageResponse[2] & 0x01) == 0x01; decoded.QueueAlgorithm = (byte)((pageResponse[3] & 0xF0) >> 4); decoded.QErr = (byte)((pageResponse[3] & 0x06) >> 1); decoded.DQue |= (pageResponse[3] & 0x01) == 0x01; decoded.EECA |= (pageResponse[4] & 0x80) == 0x80; decoded.RAENP |= (pageResponse[4] & 0x04) == 0x04; decoded.UAAENP |= (pageResponse[4] & 0x02) == 0x02; decoded.EAENP |= (pageResponse[4] & 0x01) == 0x01; decoded.ReadyAENHoldOffPeriod = (ushort)((pageResponse[6] << 8) + pageResponse[7]); if(pageResponse.Length < 10) return decoded; // SPC-1 decoded.GLTSD |= (pageResponse[2] & 0x02) == 0x02; decoded.RAC |= (pageResponse[4] & 0x40) == 0x40; decoded.SWP |= (pageResponse[4] & 0x08) == 0x08; decoded.BusyTimeoutPeriod = (ushort)((pageResponse[8] << 8) + pageResponse[9]); // SPC-2 decoded.TST = (byte)((pageResponse[2] & 0xE0) >> 5); decoded.TAS |= (pageResponse[4] & 0x80) == 0x80; decoded.AutoloadMode = (byte)(pageResponse[5] & 0x07); decoded.BusyTimeoutPeriod = (ushort)((pageResponse[10] << 8) + pageResponse[11]); // SPC-3 decoded.TMF_ONLY |= (pageResponse[2] & 0x10) == 0x10; decoded.D_SENSE |= (pageResponse[2] & 0x04) == 0x04; decoded.UA_INTLCK_CTRL = (byte)((pageResponse[4] & 0x30) >> 4); decoded.TAS |= (pageResponse[5] & 0x40) == 0x40; decoded.ATO |= (pageResponse[5] & 0x80) == 0x80; // SPC-5 decoded.DPICZ |= (pageResponse[2] & 0x08) == 0x08; decoded.NUAR |= (pageResponse[3] & 0x08) == 0x08; decoded.ATMPE |= (pageResponse[5] & 0x20) == 0x20; decoded.RWWP |= (pageResponse[5] & 0x10) == 0x10; decoded.SBLP |= (pageResponse[5] & 0x08) == 0x08; return decoded; } public static string PrettifyModePage_0A(byte[] pageResponse) => PrettifyModePage_0A(DecodeModePage_0A(pageResponse)); public static string PrettifyModePage_0A(ModePage_0A? modePage) { if(!modePage.HasValue) return null; ModePage_0A page = modePage.Value; var sb = new StringBuilder(); sb.AppendLine(Localization.SCSI_Control_mode_page); if(page.PS) sb.AppendLine("\t" + Localization.Parameters_can_be_saved); if(page.RLEC) sb.AppendLine("\t" + Localization.If_set_target_shall_report_log_exception_conditions); if(page.DQue) sb.AppendLine("\t" + Localization.Tagged_queuing_is_disabled); if(page.EECA) sb.AppendLine("\t" + Localization.Extended_Contingent_Allegiance_is_enabled); if(page.RAENP) { sb.AppendLine("\t" + Localization. Target_may_issue_an_asynchronous_event_notification_upon_completing_its_initialization); } if(page.UAAENP) { sb.AppendLine("\t" + Localization. Target_may_issue_an_asynchronous_event_notification_instead_of_a_unit_attention_condition); } if(page.EAENP) { sb.AppendLine("\t" + Localization. Target_may_issue_an_asynchronous_event_notification_instead_of_a_deferred_error); } if(page.GLTSD) sb.AppendLine("\t" + Localization.Global_logging_target_save_disabled); if(page.RAC) sb.AppendLine("\t" + Localization.CHECK_CONDITION_should_be_reported_rather_than_a_long_busy_condition); if(page.SWP) sb.AppendLine("\t" + Localization.Software_write_protect_is_enabled); if(page.TAS) { sb.AppendLine("\t" + Localization. Tasks_aborted_by_other_initiator_s_actions_should_be_terminated_with_TASK_ABORTED); } if(page.TMF_ONLY) { sb.AppendLine("\t" + Localization. All_tasks_received_in_nexus_with_ACA_ACTIVE_is_set_and_an_ACA_condition_is_established_shall_terminate); } if(page.D_SENSE) { sb.AppendLine("\t" + Localization. Device_shall_return_descriptor_format_sense_data_when_returning_sense_data_in_the_same_transactions_as_a_CHECK_CONDITION); } if(page.ATO) sb.AppendLine("\t" + Localization.LOGICAL_BLOCK_APPLICATION_TAG_should_not_be_modified); if(page.DPICZ) sb.AppendLine("\t" + Localization.Protector_information_checking_is_disabled); if(page.NUAR) sb.AppendLine("\t" + Localization.No_unit_attention_on_release); if(page.ATMPE) sb.AppendLine("\t" + Localization.Application_Tag_mode_page_is_enabled); if(page.RWWP) sb.AppendLine("\t" + Localization.Abort_any_write_command_without_protection_information); if(page.SBLP) sb.AppendLine("\t" + Localization.Supports_block_lengths_and_protection_information); switch(page.TST) { case 0: sb.AppendLine("\t" + Localization.The_logical_unit_maintains_one_task_set_for_all_nexuses); break; case 1: sb.AppendLine("\t" + Localization.The_logical_unit_maintains_separate_task_sets_for_each_nexus); break; default: sb.AppendFormat("\t" + Localization.Unknown_Task_set_type_0, page.TST).AppendLine(); break; } switch(page.QueueAlgorithm) { case 0: sb.AppendLine("\t" + Localization.Commands_should_be_sent_strictly_ordered); break; case 1: sb.AppendLine("\t" + Localization.Commands_can_be_reordered_in_any_manner); break; default: sb.AppendFormat("\t" + Localization.Unknown_Queue_Algorithm_Modifier_0, page.QueueAlgorithm). AppendLine(); break; } switch(page.QErr) { case 0: sb.AppendLine("\t" + Localization. If_ACA_is_established_the_task_set_commands_shall_resume_after_it_is_cleared_otherwise_they_shall_terminate_with_CHECK_CONDITION); break; case 1: sb.AppendLine("\t" + Localization. All_the_affected_commands_in_the_task_set_shall_be_aborted_when_CHECK_CONDITION_is_returned); break; case 3: sb.AppendLine("\t" + Localization. Affected_commands_in_the_task_set_belonging_with_the_CHECK_CONDITION_nexus_shall_be_aborted); break; default: sb.AppendLine("\t" + Localization.Reserved_QErr_value_2_is_set); break; } switch(page.UA_INTLCK_CTRL) { case 0: sb.AppendLine("\t" + Localization.LUN_shall_clear_unit_attention_condition_reported_in_the_same_nexus); break; case 2: sb.AppendLine("\t" + Localization. LUN_shall_not_clear_unit_attention_condition_reported_in_the_same_nexus); break; case 3: sb.AppendLine("\t" + Localization. LUN_shall_not_clear_unit_attention_condition_reported_in_the_same_nexus_and_shall_establish_a_unit_attention_condition_for_the_initiator); break; default: sb.AppendLine("\t" + Localization.Reserved_UA_INTLCK_CTRL_value_1_is_set); break; } switch(page.AutoloadMode) { case 0: sb.AppendLine("\t" + Localization.On_medium_insertion_it_shall_be_loaded_for_full_access); break; case 1: sb.AppendLine("\t" + Localization. On_medium_insertion_it_shall_be_loaded_for_auxiliary_memory_access_only); break; case 2: sb.AppendLine("\t" + Localization.On_medium_insertion_it_shall_not_be_loaded); break; default: sb.AppendFormat("\t" + Localization.Reserved_autoload_mode_0_set, page.AutoloadMode).AppendLine(); break; } if(page.ReadyAENHoldOffPeriod > 0) { sb. AppendFormat( "\t" + Localization._0_ms_before_attempting_asynchronous_event_notifications_after_initialization, page.ReadyAENHoldOffPeriod).AppendLine(); } if(page.BusyTimeoutPeriod > 0) { if(page.BusyTimeoutPeriod == 0xFFFF) sb.AppendLine("\t" + Localization.There_is_no_limit_on_the_maximum_time_that_is_allowed_to_remain_busy); else { sb.AppendFormat("\t" + Localization.A_maximum_of_0_ms_are_allowed_to_remain_busy, page.BusyTimeoutPeriod * 100).AppendLine(); } } if(page.ExtendedSelfTestCompletionTime > 0) { sb.AppendFormat("\t" + Localization._0_seconds_to_complete_extended_self_test, page.ExtendedSelfTestCompletionTime); } return sb.ToString(); } #endregion Mode Page 0x0A: Control mode page #region Mode Page 0x0A subpage 0x01: Control Extension mode page /// Control Extension mode page Page code 0x0A Subpage code 0x01 32 bytes in SPC-3, SPC-4, SPC-5 public struct ModePage_0A_S01 { /// Parameters can be saved public bool PS; /// Timestamp outside this standard public bool TCMOS; /// SCSI precedence public bool SCSIP; /// Implicit Asymmetric Logical Unit Access Enabled public bool IALUAE; /// 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) { if((pageResponse?[0] & 0x40) != 0x40) return null; if((pageResponse[0] & 0x3F) != 0x0A) return null; if(pageResponse[1] != 0x01) return null; if((pageResponse[2] << 8) + pageResponse[3] + 4 != pageResponse.Length) return null; if(pageResponse.Length < 32) return null; var decoded = new ModePage_0A_S01(); decoded.PS |= (pageResponse[0] & 0x80) == 0x80; decoded.IALUAE |= (pageResponse[4] & 0x01) == 0x01; decoded.SCSIP |= (pageResponse[4] & 0x02) == 0x02; decoded.TCMOS |= (pageResponse[4] & 0x04) == 0x04; decoded.InitialPriority = (byte)(pageResponse[5] & 0x0F); return decoded; } public static string PrettifyModePage_0A_S01(byte[] pageResponse) => PrettifyModePage_0A_S01(DecodeModePage_0A_S01(pageResponse)); public static string PrettifyModePage_0A_S01(ModePage_0A_S01? modePage) { if(!modePage.HasValue) return null; ModePage_0A_S01 page = modePage.Value; var sb = new StringBuilder(); sb.AppendLine(Localization.SCSI_Control_extension_page); if(page.PS) sb.AppendLine("\t" + Localization.Parameters_can_be_saved); if(page.TCMOS) { if(page.SCSIP) { sb.AppendLine("\t" + Localization. S01_Timestamp_can_be_initialized_by_methods_outside_of_the_SCSI_standards_but_SCSI_SET_TIMESTAMP_shall_take_precedence_over_them); } else { sb.AppendLine("\t" + Localization. Timestamp_can_be_initialized_by_methods_outside_of_the_SCSI_standards); } } if(page.IALUAE) sb.AppendLine("\t" + Localization.Implicit_Asymmetric_Logical_Unit_Access_is_enabled); sb.AppendFormat("\t" + Localization.Initial_priority_is_0, page.InitialPriority).AppendLine(); if(page.DLC) sb.AppendLine("\t" + Localization.Device_will_not_degrade_performance_to_extend_its_life); if(page.MaximumSenseLength > 0) { sb.AppendFormat("\t" + Localization.Maximum_sense_data_would_be_0_bytes, page.MaximumSenseLength). AppendLine(); } return sb.ToString(); } #endregion Mode Page 0x0A subpage 0x01: Control Extension mode page }