// /*************************************************************************** // The Disc Image Chef // ---------------------------------------------------------------------------- // // Filename : Sense.cs // Version : 1.0 // Author(s) : Natalia Portillo // // Component : Component // // Revision : $Revision$ // Last change by : $Author$ // Date : $Date$ // // --[ Description ] ---------------------------------------------------------- // // Description // // --[ License ] -------------------------------------------------------------- // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program 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 General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // // ---------------------------------------------------------------------------- // Copyright (C) 2011-2015 Claunia.com // ****************************************************************************/ // //$Id$ using System; using System.Text; namespace DiscImageChef.Decoders.SCSI { public enum SenseType { StandardSense, ExtendedSenseFixedCurrent, ExtendedSenseFixedPast, ExtendedSenseDescriptorCurrent, ExtendedSenseDescriptorPast, Invalid, Unknown } public struct StandardSense { /// /// If set, is valid /// public bool AddressValid; /// /// Error class, 0 to 6 /// public byte ErrorClass; /// /// Error type /// public byte ErrorType; /// /// Private usage /// public byte Private; /// /// LBA where error happened /// public uint LBA; } public enum SenseKeys : byte { /// /// No information to be reported, but bits should be checked /// NoSense = 0, /// /// Target performed some recovery to successfully complete last command /// RecoveredError = 1, /// /// Target is not ready /// NotReady = 2, /// /// Non-recoverable medium error occurred /// MediumError = 3, /// /// Non-recoverable hardware error occurred /// HardwareError = 4, /// /// Target has received an illegal request /// IllegalRequest = 5, /// /// Target requires initiator attention /// UnitAttention = 6, /// /// A protected command has been denied /// DataProtect = 7, /// /// A blank block has been tried to read or a non-rewritable one to write /// BlankCheck = 8, /// /// For private/vendor usage /// PrivateUse = 9, /// /// COPY command aborted /// CopyAborted = 0xA, /// /// Command aborted /// AbortedCommand = 0xB, /// /// SEARCH command has been satisfied /// Equal = 0xC, /// /// End-of-medium reached with data remaining in buffer /// VolumeOverflow = 0xD, /// /// COMPARE failed /// Miscompare = 0xE, /// /// Reserved /// Reserved = 0xF } public struct FixedSense { /// /// If set, is valid /// public bool InformationValid; /// /// Contains number of current segment descriptor /// public byte SegmentNumber; /// /// If set indicates current command has read a filemark or a setmark /// public bool Filemark; /// /// If set indicates device has arrived end-of-medium /// public bool EOM; /// /// Means the requested logical block length did not match the logical block length on the medium /// public bool ILI; /// /// Contains the sense key /// public SenseKeys SenseKey; /// /// Additional information /// public uint Information; /// /// Additional sense length /// public byte AdditionalLength; /// /// Command specific information field /// public uint CommandSpecific; /// /// Additional sense code /// public byte ASC; /// /// Additional sense code qualifier /// public byte ASCQ; public byte FieldReplaceable; /// /// If set, is valid /// public bool SKSV; public uint SenseKeySpecific; public byte[] AdditionalSense; } public static class Sense { /// /// Gets the SCSI SENSE type to help chosing the correct decoding function /// /// The type. /// Sense bytes. public static SenseType GetType(byte[] sense) { if (sense == null) return SenseType.Invalid; if (sense.Length < 4) return SenseType.Invalid; if ((sense[0] & 0x70) != 0x70) return sense.Length != 4 ? SenseType.Invalid : SenseType.StandardSense; switch (sense[0] & 0x0F) { case 0: return SenseType.ExtendedSenseFixedCurrent; case 1: return SenseType.ExtendedSenseFixedPast; case 2: return SenseType.ExtendedSenseDescriptorCurrent; case 3: return SenseType.ExtendedSenseDescriptorPast; default: return SenseType.Unknown; } } public static StandardSense? DecodeStandard(byte[] sense) { if (GetType(sense) != SenseType.StandardSense) return null; StandardSense decoded = new StandardSense(); decoded.AddressValid |= (sense[0] & 0x80) == 0x80; decoded.ErrorClass = (byte)((sense[0] & 0x70) >> 4); decoded.ErrorType = (byte)(sense[0] & 0x0F); decoded.Private = (byte)((sense[1] & 0x80) >> 4); decoded.LBA = (uint)(((sense[1] & 0x0F) << 16) + (sense[2] << 8) + sense[3]); return decoded; } public static FixedSense? DecodeFixed(byte[] sense) { string foo; return DecodeFixed(sense, out foo); } public static FixedSense? DecodeFixed(byte[] sense, out string senseDescription) { senseDescription = null; if((sense[0] & 0x7F) != 0x70 || (sense[0] & 0x7F) != 0x71) return null; if (sense.Length < 8) return null; FixedSense decoded = new FixedSense(); decoded.InformationValid |= (sense[0] & 0x80) == 0x80; decoded.SegmentNumber = sense[1]; decoded.Filemark |= (sense[2] & 0x80) == 0x80; decoded.EOM |= (sense[2] & 0x40) == 0x40; decoded.ILI |= (sense[2] & 0x20) == 0x20; decoded.SenseKey = (SenseKeys)(sense[2] & 0x0F); decoded.Information = (uint)((sense[3] << 24) + (sense[4] << 16) + (sense[5] << 8) + sense[6]); decoded.AdditionalLength = sense[7]; if (sense.Length != decoded.AdditionalLength + 8) return decoded; if(sense.Length >= 12) decoded.CommandSpecific = (uint)((sense[8] << 24) + (sense[9] << 16) + (sense[10] << 8) + sense[11]); if (sense.Length >= 14) { decoded.ASC = sense[12]; decoded.ASCQ = sense[13]; senseDescription = GetSenseDescription(decoded.ASC, decoded.ASCQ); } if (sense.Length >= 15) decoded.FieldReplaceable = sense[14]; if(sense.Length >= 18) decoded.SenseKeySpecific = (uint)((sense[15] << 16) + (sense[16] << 8) + sense[17]); if (sense.Length > 18) { decoded.AdditionalSense = new byte[sense.Length - 18]; Array.Copy(sense, 18, decoded.AdditionalSense, 0, decoded.AdditionalSense.Length); } return decoded; } public static string PrettifySense(byte[] sense) { SenseType type = GetType(sense); switch (type) { case SenseType.StandardSense: return PrettifySense(DecodeStandard(sense)); case SenseType.ExtendedSenseFixedCurrent: case SenseType.ExtendedSenseFixedPast: return PrettifySense(DecodeFixed(sense)); default: return null; } } public static string PrettifySense(StandardSense? sense) { if (!sense.HasValue) return null; return sense.Value.AddressValid ? String.Format("Error class {0} type {1} happened on block {2}\n", sense.Value.ErrorClass, sense.Value.ErrorType, sense.Value.LBA) : String.Format("Error class {0} type {1}\n", sense.Value.ErrorClass, sense.Value.ErrorType); } public static string PrettifySense(FixedSense? sense) { if (!sense.HasValue) return null; FixedSense decoded = sense.Value; StringBuilder sb = new StringBuilder(); sb.AppendFormat("SCSI SENSE: {0}", GetSenseKey(decoded.SenseKey)).AppendLine(); if (decoded.SegmentNumber > 0) sb.AppendFormat("On segment {0}", decoded.SegmentNumber).AppendLine(); if (decoded.Filemark) sb.AppendLine("Filemark or setmark found"); if (decoded.EOM) sb.AppendLine("End-of-medium/partition found"); if (decoded.ILI) sb.AppendLine("Incorrect length indicator"); if (decoded.InformationValid) sb.AppendFormat("On logical block {0}", decoded.Information); if (decoded.AdditionalLength < 6) return sb.ToString(); sb.AppendLine(GetSenseDescription(decoded.ASC, decoded.ASCQ)); if (decoded.AdditionalLength < 10) return sb.ToString(); if (decoded.SKSV) { switch (decoded.SenseKey) { case SenseKeys.IllegalRequest: { if ((decoded.SenseKeySpecific & 0x400000) == 0x400000) sb.AppendLine("Illegal field in CDB"); else sb.AppendLine("Illegal field in data parameters"); if ((decoded.SenseKeySpecific & 0x200000) == 0x200000) sb.AppendFormat("Invalid value in bit {0} in field {1} of CDB", (decoded.SenseKeySpecific & 0x70000) >> 16, decoded.SenseKeySpecific & 0xFFFF).AppendLine(); else sb.AppendFormat("Invalid value in field {0} of CDB", decoded.SenseKeySpecific & 0xFFFF).AppendLine(); } break; case SenseKeys.NotReady: sb.AppendFormat("Format progress {0:P}", (double)(decoded.SenseKeySpecific & 0xFFFF) / 65536).AppendLine(); break; case SenseKeys.RecoveredError: case SenseKeys.HardwareError: case SenseKeys.MediumError: sb.AppendFormat("Actual retry count is {0}", decoded.SenseKeySpecific & 0xFFFF).AppendLine(); break; } } return sb.ToString(); } public static string GetSenseKey(SenseKeys key) { switch (key) { case SenseKeys.AbortedCommand: return "ABORTED COMMAND"; case SenseKeys.BlankCheck: return "BLANK CHECK"; case SenseKeys.CopyAborted: return "COPY ABORTED"; case SenseKeys.DataProtect: return "DATA PROTECT"; case SenseKeys.Equal: return "EQUAL"; case SenseKeys.HardwareError: return "HARDWARE ERROR"; case SenseKeys.IllegalRequest: return "ILLEGAL REQUEST"; case SenseKeys.MediumError: return "MEDIUM ERROR"; case SenseKeys.Miscompare: return "MISCOMPARE"; case SenseKeys.NoSense: return "NO SENSE"; case SenseKeys.PrivateUse: return "PRIVATE USE"; case SenseKeys.RecoveredError: return "RECOVERED ERROR"; case SenseKeys.Reserved: return "RETURN"; case SenseKeys.UnitAttention: return "UNIT ATTENTION"; case SenseKeys.VolumeOverflow: return "VOLUME OVERFLOW"; default: return "UNKNOWN"; } } public static string GetSenseDescription(byte ASC, byte ASCQ) { switch (ASC) { case 0x00: switch (ASCQ) { case 0x00: return "NO ADDITIONAL SENSE INFORMATION"; case 0x01: return "FILEMARK DETECTED"; case 0x02: return "END-OF-PARTITION/MEDIUM DETECTED"; case 0x03: return "SETMARK DETECTED"; case 0x04: return "BEGINNING-OF-PARTITION/MEDIUM DETECTED"; case 0x05: return "END-OF-DATA DETECTED"; case 0x06: return "I/O PROCESS TERMINATED"; case 0x11: return "AUDIO PLAY OPERATION IN PROGRESS"; case 0x12: return "AUDIO PLAY OPERATION PAUSED"; case 0x13: return "AUDIO PLAY OPERATION SUCCESSFULLY COMPLETED"; case 0x14: return "AUDIO PLAY OPERATION STOPPED DUE TO ERROR"; case 0x15: return "NO CURRENT AUDIO STATUS TO RETURN"; } break; case 0x01: switch (ASCQ) { case 0x00: return "NO INDEX/SECTOR SIGNAL"; } break; case 0x02: switch (ASCQ) { case 0x00: return "NO SEEK COMPLETE"; } break; case 0x03: switch (ASCQ) { case 0x00: return "PERIPHERAL DEVICE WRITE FAULT"; case 0x01: return "NO WRITE CURRENT"; case 0x02: return "EXCESSIVE WRITE ERRORS"; } break; case 0x04: switch (ASCQ) { case 0x00: return "LOGICAL UNIT NOT READY, CAUSE NOT REPORTABLE"; case 0x01: return "LOGICAL UNIT IS IN PROCESS OF BECOMING READY"; case 0x02: return "LOGICAL UNIT NOT READY, INITIALIZING COMMAND REQUIRED"; case 0x03: return "LOGICAL UNIT NOT READY, MANUAL INTERVENTION REQUIRED"; case 0x04: return "LOGICAL UNIT NOT READY, FORMAT IN PROGRESS"; } break; case 0x05: switch (ASCQ) { case 0x00: return "LOGICAL UNIT DOES NOT RESPOND TO SELECTION"; } break; case 0x06: switch (ASCQ) { case 0x00: return "REFERENCE POSITION FOUND"; } break; case 0x07: switch (ASCQ) { case 0x00: return "MULTIPLE PERIPHERAL DEVICES SELECTED"; } break; case 0x08: switch (ASCQ) { case 0x00: return "LOGICAL UNIT COMMUNICATION FAILURE"; case 0x01: return "LOGICAL UNIT COMMUNICATION TIME-OUT"; case 0x02: return "LOGICAL UNIT COMMUNICATION PARITY ERROR"; } break; case 0x09: switch (ASCQ) { case 0x00: return "TRACK FLOLLOWING ERROR"; case 0x01: return "TRACKING SERVO FAILURE"; case 0x02: return "FOCUS SERVO FAILURE"; case 0x03: return "SPINDLE SERVO FAILURE"; } break; case 0x0A: switch (ASCQ) { case 0x00: return "ERROR LOG OVERFLOW"; } break; case 0x0C: switch (ASCQ) { case 0x00: return "WRITE ERROR"; case 0x01: return "WRITE ERROR RECOVERED WITH AUTO REALLOCATION"; case 0x02: return "WRITE ERROR - AUTO REALLOCATION FAILED"; } break; case 0x10: switch (ASCQ) { case 0x00: return "ID CRC OR ECC ERROR"; } break; case 0x11: switch (ASCQ) { case 0x00: return "UNRECOVERED READ ERROR"; case 0x01: return "READ RETRIES EXHAUSTED"; case 0x02: return "ERROR TOO LONG TO CORRECT"; case 0x03: return "MULTIPLE READ ERRORS"; case 0x04: return "UNRECOVERED READ ERROR - AUTO REALLOCATE FAILED"; case 0x05: return "L-EC UNCORRECTABLE ERROR"; case 0x06: return "CIRC UNRECOVERED ERROR"; case 0x07: return "DATA RESYNCHRONIZATION ERROR"; case 0x08: return "INCOMPLETE BLOCK READ"; case 0x09: return "NO GAP FOUND"; case 0x0A: return "MISCORRECTED ERROR"; case 0x0B: return "UNRECOVERED READ ERROR - RECOMMENDED REASSIGNMENT"; case 0x0C: return "UNRECOVERED READ ERROR - RECOMMENDED REWRITE THE DATA"; } break; case 0x12: switch (ASCQ) { case 0x00: return "ADDRESS MARK NOT FOUND FOR ID FIELD"; } break; case 0x13: switch (ASCQ) { case 0x00: return "ADDRESS MARK NOT FOUND FOR DATA FIELD"; } break; case 0x14: switch (ASCQ) { case 0x00: return "RECORDED ENTITY NOT FOUND"; case 0x01: return "RECORD NOT FOUND"; case 0x02: return "FILEMARK OR SETMARK NOT FOUND"; case 0x03: return "END-OF-DATA NOT FOUND"; case 0x04: return "BLOCK SEQUENCE ERROR"; } break; case 0x15: switch (ASCQ) { case 0x00: return "RANDOM POSITIONING ERROR"; case 0x01: return "MECHANICAL POSITIONING ERROR"; case 0x02: return "POSITIONING ERROR DETECTED BY READ OF MEDIUM"; } break; case 0x16: switch (ASCQ) { case 0x00: return "DATA SYNCHRONIZATION MARK ERROR"; } break; case 0x17: switch (ASCQ) { case 0x00: return "RECOVERED DATA WITH NO ERROR CORRECTION APPLIED"; case 0x01: return "RECOVERED DATA WITH RETRIES"; case 0x02: return "RECOVERED DATA WITH POSITIVE HEAD OFFSET"; case 0x03: return "RECOVERED DATA WITH NEGATIVE HEAD OFFSET"; case 0x04: return "RECOVERED DATA WITH RETRIES AND/OR CIRC APPLIED"; case 0x05: return "RECOVERED DATA USING PREVIOUS SECTOR ID"; case 0x06: return "RECOVERED DATA WITHOUT ECC - DATA AUTO-REALLOCATED"; case 0x07: return "RECOVERED DATA WITHOUT ECC - RECOMMENDED REASSIGNMENT"; case 0x08: return "RECOVERED DATA WITHOUT ECC - RECOMMENDED REWRITE"; } break; case 0x18: switch (ASCQ) { case 0x00: return "RECOVERED DATA WITH ERROR CORRECTION APPLIED"; case 0x01: return "RECOVERED DATA WITH ERROR CORRECTION & RETRIES APPLIED"; case 0x02: return "RECOVERED DATA - DATA AUTO-REALLOCATED"; case 0x03: return "RECOVERED DATA WITH CIRC"; case 0x04: return "RECOVERED DATA WITH L-EC"; case 0x05: return "RECOVERED DATA - RECOMMENDED REASSIGNMENT"; case 0x06: return "RECOVERED DATA - RECOMMENDED REWRITE"; } break; case 0x19: switch (ASCQ) { case 0x00: return "DEFECT LIST ERROR"; case 0x01: return "DEFECT LIST NOT AVAILABLE"; case 0x02: return "DEFECT LIST ERROR IN PRIMARY LIST"; case 0x03: return "DEFECT LIST ERROR IN GROWN LIST"; } break; case 0x1A: switch (ASCQ) { case 0x00: return "PARAMETER LIST LENGTH ERROR"; } break; case 0x1B: switch (ASCQ) { case 0x00: return "SYNCHRONOUS DATA TRANSFER ERROR"; } break; case 0x1C: switch (ASCQ) { case 0x00: return "DEFECT LIST NOT FOUND"; case 0x01: return "PRIMARY DEFECT LIST NOT FOUND"; case 0x02: return "GROWN DEFECT LIST NOT FOUND"; } break; case 0x1D: switch (ASCQ) { case 0x00: return "MISCOMPARE DURING VERIFY OPERATION"; } break; case 0x1E: switch (ASCQ) { case 0x00: return "RECOVERED ID WITH ECC"; } break; case 0x20: switch (ASCQ) { case 0x00: return "INVALID COMMAND OPERATION CODE"; } break; case 0x21: switch (ASCQ) { case 0x00: return "LOGICAL BLOCK ADDRESS OUT OF RANGE"; case 0x01: return "INVALID ELEMENT ADDRESS"; } break; case 0x22: switch (ASCQ) { case 0x00: return "ILLEGAL FUNCTION"; } break; case 0x24: switch (ASCQ) { case 0x00: return "ILLEGAL FIELD IN CDB"; } break; case 0x25: switch (ASCQ) { case 0x00: return "LOGICAL UNIT NOT SUPPORTED"; } break; case 0x26: switch (ASCQ) { case 0x00: return "INVALID FIELD IN PARAMETER LIST"; case 0x01: return "PARAMETER NOT SUPPORTED"; case 0x02: return "PARAMETER VALUE INVALID"; case 0x03: return "THRESHOLD PARAMETERS NOT SUPPORTED"; } break; case 0x27: switch (ASCQ) { case 0x00: return "WRITE PROTECTED"; } break; case 0x28: switch (ASCQ) { case 0x00: return "NOT READY TO READY TRANSITION (MEDIUM MAY HAVE CHANGED)"; case 0x01: return "IMPORT OR EXPORT ELEMENT ACCESSED"; } break; case 0x29: switch (ASCQ) { case 0x00: return "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED"; } break; case 0x2A: switch (ASCQ) { case 0x00: return "PARAMETERS CHANGED"; case 0x01: return "MODE PARAMETERS CHANGED"; case 0x02: return "LOG PARAMETERS CHANGED"; } break; case 0x2B: switch (ASCQ) { case 0x00: return "COPY CANNOT EXECUTE SINCE HOST CANNOT DISCONNECT"; } break; case 0x2C: switch (ASCQ) { case 0x00: return "COMMAND SEQUENCE ERROR"; case 0x01: return "TOO MANY WINDOWS SPECIFIED"; case 0x02: return "INVALID COMBINATION OF WINDOWS SPECIFIED"; } break; case 0x2D: switch (ASCQ) { case 0x00: return "OVERWRITE ERROR ON UPDATE IN PLACE"; } break; case 0x2F: switch (ASCQ) { case 0x00: return "COMMANDS CLEARED BY ANOTHER INITIATOR"; } break; case 0x30: switch (ASCQ) { case 0x00: return "INCOMPATIBLE MEDIUM INSTALLED"; case 0x01: return "CANNOT READ MEDIUM - UNKNOWN FORMAT"; case 0x02: return "CANNOT READ MEDIUM - INCOMPATIBLE FORMAT"; case 0x03: return "CLEANING CARTRIDGE INSTALLED"; } break; case 0x31: switch (ASCQ) { case 0x00: return "MEDIUM FORMAT CORRUPTED"; case 0x01: return "FORMAT COMMAND FAILED"; } break; case 0x32: switch (ASCQ) { case 0x00: return "NO DEFECT SPARE LOCATION AVAILABLE"; case 0x01: return "DEFECT LIST UPDATE FAILURE"; } break; case 0x33: switch (ASCQ) { case 0x00: return "TAPE LENGTH ERROR"; } break; case 0x36: switch (ASCQ) { case 0x00: return "RIBBON, INK, OR TONER FAILURE"; } break; case 0x37: switch (ASCQ) { case 0x00: return "ROUNDED PARAMETER"; } break; case 0x39: switch (ASCQ) { case 0x00: return "SAVING PARAMETERS NOT SUPPORTED"; } break; case 0x3A: switch (ASCQ) { case 0x00: return "MEDIUM NOT PRESENT"; } break; case 0x3B: switch (ASCQ) { case 0x00: return "SEQUENTIAL POSITIONING ERROR"; case 0x01: return "TAPE POSITION ERROR AT BEGINNING-OF-MEDIUM"; case 0x02: return "TAPE POSITION ERROR AT END-OF-MEDIUM"; case 0x03: return "TAPE OR ELECTRONIC VERTICAL FORMS UNIT NOT READY"; case 0x04: return "SLEW FAILURE"; case 0x05: return "PAPER JAM"; case 0x06: return "FAILED TO SENSE TOP-OF-FORM"; case 0x07: return "FAILED TO SENSE BOTTOM-OF-FORM"; case 0x08: return "REPOSITION ERROR"; case 0x09: return "READ PAST END OF MEDIUM"; case 0x0A: return "READ PAST BEGINNING OF MEDIUM"; case 0x0B: return "POSITION PAST END OF MEDIUM"; case 0x0C: return "POSITION PAST BEGINNING OF MEDIUM"; case 0x0D: return "MEDIUM DESTINATION ELEMENT FULL"; case 0x0E: return "MEDIUM SOURCE ELEMENT EMPTY"; } break; case 0x3D: switch (ASCQ) { case 0x00: return "INVALID BITS IN IDENTIFY MESSAGE"; } break; case 0x3E: switch (ASCQ) { case 0x00: return "LOGICAL UNIT HAS NOT SELF-CONFIGURED YET"; } break; case 0x3F: switch (ASCQ) { case 0x00: return "TARGET OPERATING CONDITIONS HAVE CHANGED"; case 0x01: return "MICROCODE HAS BEEN CHANGED"; case 0x02: return "CHANGED OPERATING DEFINITION"; case 0x03: return "INQUIRY DATA HAS CHANGED"; } break; case 0x40: switch (ASCQ) { case 0x00: return "RAM FAILURE"; default: return String.Format("DIAGNOSTIC FAILURE ON COMPONENT {0:X2}h", ASCQ); } case 0x41: switch (ASCQ) { case 0x00: return "DATA PATH FAILURE"; } break; case 0x42: switch (ASCQ) { case 0x00: return "POWER-ON OR SELF-TEST FAILURE"; } break; case 0x43: switch (ASCQ) { case 0x00: return "MESSAGE ERROR"; } break; case 0x44: switch (ASCQ) { case 0x00: return "INTERNAL TARGET FAILURE"; } break; case 0x45: switch (ASCQ) { case 0x00: return "SELECT OR RESELECT FAILURE"; } break; case 0x46: switch (ASCQ) { case 0x00: return "UNSUCCESSFUL SOFT RESET"; } break; case 0x47: switch (ASCQ) { case 0x00: return "SCSI PARITY ERROR"; } break; case 0x48: switch (ASCQ) { case 0x00: return "INITIATOR DETECTED ERROR MESSAGE RECEIVED"; } break; case 0x49: switch (ASCQ) { case 0x00: return "INVALID MESSAGE ERROR"; } break; case 0x4A: switch (ASCQ) { case 0x00: return "COMMAND PHASE ERROR"; } break; case 0x4B: switch (ASCQ) { case 0x00: return "DATA PHASE ERROR"; } break; case 0x4C: switch (ASCQ) { case 0x00: return "LOGICAL UNIT FAILED SELF-CONFIGURATION"; } break; case 0x4E: switch (ASCQ) { case 0x00: return "OVERLAPPED COMMANDS ATTEMPTED"; } break; case 0x50: switch (ASCQ) { case 0x00: return "WRITE APPEND ERROR"; case 0x01: return "WRITE APPEND POSITION ERROR"; case 0x02: return "POSITION ERROR RELATED TO TIMING"; } break; case 0x51: switch (ASCQ) { case 0x00: return "ERASE FAILURE"; } break; case 0x52: switch (ASCQ) { case 0x00: return "CARTRIDGE FAULT"; } break; case 0x53: switch (ASCQ) { case 0x00: return "MEDIA LOAD OR EJECT FAILED"; case 0x01: return "UNLOAD TAPE FAILURE"; case 0x02: return "MEDIUM REMOVAL PREVENTED"; } break; case 0x54: switch (ASCQ) { case 0x00: return "SCSI TO HOST SYSTEM INTERFACE FAILURE"; } break; case 0x55: switch (ASCQ) { case 0x00: return "SYSTEM RESOURCE FAILURE"; } break; case 0x57: switch (ASCQ) { case 0x00: return "UNABLE TO RECOVER TABLE-OF-CONTENTS"; } break; case 0x58: switch (ASCQ) { case 0x00: return "GENERATION DOES NOT EXIST"; } break; case 0x59: switch (ASCQ) { case 0x00: return "UPDATED BLOCK READ"; } break; case 0x5A: switch (ASCQ) { case 0x00: return "OPERATOR REQUEST OR STATE CHANGE INPUT"; case 0x01: return "OPERATOR MEDIUM REMOVAL REQUEST"; case 0x02: return "OPERATOR SELECTED WRITE PROTECT"; case 0x03: return "OPERATOR SELECTED WRITE PERMIT"; } break; case 0x5B: switch (ASCQ) { case 0x00: return "LOG EXCEPTION"; case 0x01: return "THRESHOLD CONDITION MET"; case 0x02: return "LOG COUNTER AT MAXIMUM"; case 0x03: return "LOG LIST CODES EXHAUSTED"; } break; case 0x5C: switch (ASCQ) { case 0x00: return "RPL STATUS CHANGE"; case 0x01: return "SPINDLES SYNCHRONIZED"; case 0x02: return "SPINDLES NOT SYNCHRONIZED"; } break; case 0x60: switch (ASCQ) { case 0x00: return "LAMP FAILURE"; } break; case 0x61: switch (ASCQ) { case 0x00: return "VIDEO ACQUISTION ERROR"; case 0x01: return "UNABLE TO ACQUIRE VIDEO"; case 0x02: return "OUT OF FOCUS"; } break; case 0x62: switch (ASCQ) { case 0x00: return "SCAN HEAD POSITIONING ERROR"; } break; case 0x63: switch (ASCQ) { case 0x00: return "END OF USER AREA ENCOUNTERED ON THIS TRACK"; } break; case 0x64: switch (ASCQ) { case 0x00: return "ILLEGAL MODE FOR THIS TRACK"; } break; } return ASC >= 0x80 ? ASCQ >= 0x80 ? String.Format("VENDOR-SPECIFIC ASC {0:X2}h WITH VENDOR-SPECIFIC ASCQ {1:X2}h", ASC, ASCQ) : String.Format("VENDOR-SPECIFIC ASC {0:X2}h WITH ASCQ {1:X2}h", ASC, ASCQ) : ASCQ >= 0x80 ? String.Format("ASC {0:X2}h WITH VENDOR-SPECIFIC ASCQ {1:X2}h", ASC, ASCQ) : String.Format("ASC {0:X2}h WITH ASCQ {1:X2}h", ASC, ASCQ); } } }