From a7cca59a29c986d3763a5e637f77e83fcc1a7a18 Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Sun, 25 Oct 2015 05:39:25 +0000 Subject: [PATCH] Implemented decoding mode page 0Ah. --- ChangeLog | 5 + SCSI/Modes.cs | 347 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 350 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index e22c79a..4b0a5c5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2015-10-25 Natalia Portillo + + * SCSI/Modes.cs: + Implemented decoding mode page 0Ah. + 2015-10-25 Natalia Portillo * SCSI/Modes.cs: diff --git a/SCSI/Modes.cs b/SCSI/Modes.cs index 468956d..c361f45 100644 --- a/SCSI/Modes.cs +++ b/SCSI/Modes.cs @@ -46,6 +46,7 @@ namespace DiscImageChef.Decoders.SCSI { Default = 0x00, #region Medium Types defined in ECMA-111 for Direct-Access devices + /// /// ECMA-54: 200 mm Flexible Disk Cartridge using Two-Frequency Recording at 13262 ftprad on One Side /// @@ -81,6 +82,7 @@ namespace DiscImageChef.Decoders.SCSI #endregion Medium Types defined in ECMA-111 for Direct-Access devices #region Medium Types defined in SCSI-2 for Direct-Access devices + /// /// Unspecified single sided flexible disk /// @@ -112,6 +114,7 @@ namespace DiscImageChef.Decoders.SCSI #endregion Medium Types defined in SCSI-2 for Direct-Access devices #region Medium Types defined in SCSI-3 SBC-1 for Optical devices + /// /// Read-only medium /// @@ -139,6 +142,7 @@ namespace DiscImageChef.Decoders.SCSI #endregion Medium Types defined in SCSI-3 SBC-1 for Optical devices #region Medium Types defined in SCSI-2 for MultiMedia devices + /// /// 120 mm CD-ROM /// @@ -163,6 +167,7 @@ namespace DiscImageChef.Decoders.SCSI /// 80 mm Compact Disc with data and audio /// MixedCD_80 = 0x07 + #endregion Medium Types defined in SCSI-2 for MultiMedia devices } @@ -170,6 +175,7 @@ namespace DiscImageChef.Decoders.SCSI { Default = 0x00, #region Density Types defined in ECMA-111 for Direct-Access devices + /// /// 7958 flux transitions per radian /// @@ -185,6 +191,7 @@ namespace DiscImageChef.Decoders.SCSI #endregion Density Types defined in ECMA-111 for Direct-Access devices #region Density Types defined in ECMA-111 for Sequential-Access devices + /// /// ECMA-62 & ANSI X3.22-1983: 12,7 mm 9-Track Magnetic Tape, 32 ftpmm, NRZI, 32 cpmm /// @@ -216,6 +223,7 @@ namespace DiscImageChef.Decoders.SCSI #endregion Density Types defined in ECMA-111 for Sequential-Access devices #region Density Types defined in SCSI-2 for Sequential-Access devices + /// /// ANXI X3.136-1986: 6,3 mm 4 or 9-Track Magnetic Tape Cartridge, 315 bpmm, GCR /// @@ -279,6 +287,7 @@ namespace DiscImageChef.Decoders.SCSI #endregion Density Types defined in SCSI-2 for Sequential-Access devices #region Density Types defined in SCSI-2 for MultiMedia devices + /// /// User data only /// @@ -298,6 +307,7 @@ namespace DiscImageChef.Decoders.SCSI #endregion Density Types defined in SCSI-2 for MultiMedia devices #region Density Types defined in SCSI-2 for Optical devices + /// /// ISO/IEC 10090: 86 mm Read/Write single-sided optical disc with 12500 tracks /// @@ -334,6 +344,7 @@ namespace DiscImageChef.Decoders.SCSI /// ANSI X3.200: 356 mm double-sided optical disc with 56350 tracks /// X3_200 = 0x09 + #endregion Density Types defined in SCSI-2 for Optical devices } @@ -365,7 +376,7 @@ namespace DiscImageChef.Decoders.SCSI if (modeResponse[3] > 0) { - header.BlockDescriptors = new BlockDescriptor[modeResponse[3]/8]; + header.BlockDescriptors = new BlockDescriptor[modeResponse[3] / 8]; for (int i = 0; i < header.BlockDescriptors.Length; i++) { header.BlockDescriptors[i].Density = (DensityType)modeResponse[0 + i * 8 + 4]; @@ -901,7 +912,7 @@ namespace DiscImageChef.Decoders.SCSI if (blockDescLength > 0) { - header.BlockDescriptors = new BlockDescriptor[blockDescLength/8]; + header.BlockDescriptors = new BlockDescriptor[blockDescLength / 8]; for (int i = 0; i < header.BlockDescriptors.Length; i++) { header.BlockDescriptors[i].Density = (DensityType)modeResponse[0 + i * 8 + 8]; @@ -944,6 +955,338 @@ namespace DiscImageChef.Decoders.SCSI { return PrettifyModeHeader(DecodeModeHeader10(modeResponse, deviceType), deviceType); } + + #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 + /// + 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 == null) + return null; + + if ((pageResponse[0] & 0x3F) != 0x0A) + return null; + + if (pageResponse[1] + 2 != pageResponse.Length) + return null; + + if (pageResponse.Length < 8) + return null; + + ModePage_0A 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) + { + return PrettifyModePage_0A(DecodeModePage_0A(pageResponse)); + } + + public static string PrettifyModePage_0A(ModePage_0A? modePage) + { + if (!modePage.HasValue) + return null; + + ModePage_0A page = modePage.Value; + StringBuilder sb = new StringBuilder(); + + sb.AppendLine("SCSI Control mode page:"); + + if (page.PS) + sb.AppendLine("\tParameters can be saved"); + if (page.RLEC) + sb.AppendLine("\tIf set, target shall report log exception conditions"); + if (page.DQue) + sb.AppendLine("\tTagged queuing is disabled"); + if (page.EECA) + sb.AppendLine("\tExtended Contingent Allegiance is enabled"); + if (page.RAENP) + sb.AppendLine("\tTarget may issue an asynchronous event notification upon completing its initialization"); + if (page.UAAENP) + sb.AppendLine("\tTarget may issue an asynchronous event notification instead of a unit attention condition"); + if (page.EAENP) + sb.AppendLine("\tTarget may issue an asynchronous event notification instead of a deferred error"); + if (page.GLTSD) + sb.AppendLine("\tGlobal logging target save disabled"); + if (page.RAC) + sb.AppendLine("\tCHECK CONDITION should be reported rather than a long busy condition"); + if (page.SWP) + sb.AppendLine("\tSoftware write protect is active"); + if (page.TAS) + sb.AppendLine("\tTasks aborted by other initiator's actions should be terminated with TASK ABORTED"); + if (page.TMF_ONLY) + sb.AppendLine("\tAll tasks received in nexus with ACA ACTIVE is set and an ACA condition is established shall terminate"); + if (page.D_SENSE) + sb.AppendLine("\tDevice shall return descriptor format sense data when returning sense data in the same transactions as a CHECK CONDITION"); + if (page.ATO) + sb.AppendLine("\tLOGICAL BLOCK APPLICATION TAG should not be modified"); + if (page.DPICZ) + sb.AppendLine("\tProtector information checking is disabled"); + if (page.NUAR) + sb.AppendLine("\tNo unit attention on release"); + if (page.ATMPE) + sb.AppendLine("\tApplication Tag mode page is enabled"); + if (page.RWWP) + sb.AppendLine("\tAbort any write command without protection information"); + if (page.SBLP) + sb.AppendLine("\tSupportes block lengths and protection information"); + + switch (page.TST) + { + case 0: + sb.AppendLine("\tThe logical unit maintains one task set for all nexuses"); + break; + case 1: + sb.AppendLine("\tThe logical unit maintains separate task sets for each nexus"); + break; + default: + sb.AppendFormat("\tUnknown Task set type {0}", page.TST).AppendLine(); + break; + } + + switch (page.QueueAlgorithm) + { + case 0: + sb.AppendLine("\tCommands should be sent strictly ordered"); + break; + case 1: + sb.AppendLine("\tCommands can be reordered in any manner"); + break; + default: + sb.AppendFormat("\tUnknown Queue Algorithm Modifier {0}", page.QueueAlgorithm).AppendLine(); + break; + } + + switch (page.QErr) + { + case 0: + sb.AppendLine("\tIf 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("\tAll the affected commands in the task set shall be aborted when CHECK CONDITION is returned"); + break; + case 3: + sb.AppendLine("\tAffected commands in the task set belonging with the CHECK CONDITION nexus shall be aborted"); + break; + default: + sb.AppendLine("\tReserved QErr value 2 is set"); + break; + } + + switch (page.UA_INTLCK_CTRL) + { + case 0: + sb.AppendLine("\tLUN shall clear unit attention condition reported in the same nexus"); + break; + case 2: + sb.AppendLine("\tLUN shall not clear unit attention condition reported in the same nexus"); + break; + case 3: + sb.AppendLine("\tLUN 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("\tReserved UA_INTLCK_CTRL value 1 is set"); + break; + } + + switch (page.AutoloadMode) + { + case 0: + sb.AppendLine("\tOn medium insertion, it shall be loaded for full access"); + break; + case 1: + sb.AppendLine("\tOn medium insertion, it shall be loaded for auxiliary memory access only"); + break; + case 2: + sb.AppendLine("\tOn medium insertion, it shall not be loaded"); + break; + default: + sb.AppendFormat("\tReserved autoload mode {0} set", page.AutoloadMode).AppendLine(); + break; + } + + if (page.ReadyAENHoldOffPeriod > 0) + sb.AppendFormat("\t{0} ms before attempting asynchronous event notifications after initialization", page.ReadyAENHoldOffPeriod).AppendLine(); + + if (page.BusyTimeoutPeriod > 0) + { + if (page.BusyTimeoutPeriod == 0xFFFF) + sb.AppendLine("\tThere is no limit on the maximum time that is allowed to remain busy"); + else + sb.AppendFormat("\tA maximum of {0} ms are allowed to remain busy", (int)page.BusyTimeoutPeriod * 100).AppendLine(); + } + + if (page.ExtendedSelfTestCompletionTime > 0) + sb.AppendFormat("\t{0} seconds to complete extended self-test", page.ExtendedSelfTestCompletionTime); + + return sb.ToString(); + } + #endregion Mode Page 0x0a: Control mode page } }