diff --git a/DiscImageChef.Decoders/ChangeLog b/DiscImageChef.Decoders/ChangeLog index 8e0c64011..67a8d7460 100644 --- a/DiscImageChef.Decoders/ChangeLog +++ b/DiscImageChef.Decoders/ChangeLog @@ -1,3 +1,7 @@ +2016-10-13 Natalia Portillo + + * EVPD.cs: Added EVPD page 89h, SCSI to ATA translation layer + 2016-10-13 Natalia Portillo * EVPD.cs: Updated page 85h to SPC-5. diff --git a/DiscImageChef.Decoders/SCSI/EVPD.cs b/DiscImageChef.Decoders/SCSI/EVPD.cs index ae7674696..b8b845770 100644 --- a/DiscImageChef.Decoders/SCSI/EVPD.cs +++ b/DiscImageChef.Decoders/SCSI/EVPD.cs @@ -33,6 +33,7 @@ using System; using System.Collections.Generic; using System.Text; +using System.Security.Policy; namespace DiscImageChef.Decoders.SCSI { @@ -972,6 +973,440 @@ namespace DiscImageChef.Decoders.SCSI #endregion EVPD Page 0x85: Management Network Addresses page + #region EVPD Page 0x86: Extended INQUIRY data page + + /// + /// Device identification page + /// Page code 0x86 + /// + public struct Page_86 + { + /// + /// The peripheral qualifier. + /// + public PeripheralQualifiers PeripheralQualifier; + /// + /// The type of the peripheral device. + /// + public PeripheralDeviceTypes PeripheralDeviceType; + /// + /// The page code. + /// + public byte PageCode; + /// + /// The length of the page. + /// + public byte PageLength; + /// + /// Indicates how a device server activates microcode + /// + public byte ActivateMicrocode; + /// + /// Protection types supported by device + /// + public byte SPT; + /// + /// Checks logical block guard field + /// + public bool GRD_CHK; + /// + /// Checks logical block application tag + /// + public bool APP_CHK; + /// + /// Checks logical block reference + /// + public bool REF_CHK; + /// + /// Supports unit attention condition sense key specific data + /// + public bool UASK_SUP; + /// + /// Supports grouping + /// + public bool GROUP_SUP; + /// + /// Supports priority + /// + public bool PRIOR_SUP; + /// + /// Supports head of queue + /// + public bool HEADSUP; + /// + /// Supports ordered + /// + public bool ORDSUP; + /// + /// Supports simple + /// + public bool SIMPSUP; + /// + /// Supports marking a block as uncorrectable + /// + public bool WU_SUP; + /// + /// Supports disabling correction on WRITE LONG + /// + public bool CRD_SUP; + /// + /// Supports a non-volatile cache + /// + public bool NV_SUP; + /// + /// Supports a volatile cache + /// + public bool V_SUP; + /// + /// Disable protection information checks + /// + public bool NO_PI_CHK; + /// + /// Protection information interval supported + /// + public bool P_I_I_SUP; + /// + /// Clears all LUNs unit attention when clearing one + /// + public bool LUICLR; + /// + /// Referrals support + /// + public bool R_SUP; + /// + /// History snapshots release effects + /// + public bool HSSRELEF; + /// + /// Capability based command security + /// + public bool CBCS; + /// + /// Indicates how it handles microcode updating with multiple nexuxes + /// + public byte Nexus; + /// + /// Time to complete extended self-test + /// + public ushort ExtendedTestMinutes; + /// + /// Power on activation support + /// + public bool POA_SUP; + /// + /// Hard reset actication + /// + public bool HRA_SUP; + /// + /// Vendor specific activation + /// + public bool VSA_SUP; + /// + /// Maximum length in bytes of sense data + /// + public byte MaximumSenseLength; + } + + public static Page_86? DecodePage_86(byte[] pageResponse) + { + if(pageResponse == null) + return null; + + if(pageResponse[1] != 0x86) + return null; + + if(pageResponse[3] + 4 != pageResponse.Length) + return null; + + if(pageResponse.Length < 64) + return null; + + Page_86 decoded = new Page_86(); + + decoded.PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5); + decoded.PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F); + decoded.PageLength = (byte)((pageResponse[2] << 4) + pageResponse[3] + 4); + + decoded.ActivateMicrocode = (byte)((pageResponse[4] & 0xC0) >> 6); + decoded.SPT = (byte)((pageResponse[4] & 0x38) >> 3); + decoded.GRD_CHK |= (pageResponse[4] & 0x04) == 0x04; + decoded.APP_CHK |= (pageResponse[4] & 0x02) == 0x02; + decoded.REF_CHK |= (pageResponse[4] & 0x01) == 0x01; + decoded.UASK_SUP |= (pageResponse[5] & 0x20) == 0x20; + decoded.GROUP_SUP |= (pageResponse[5] & 0x10) == 0x10; + decoded.PRIOR_SUP |= (pageResponse[5] & 0x08) == 0x08; + decoded.HEADSUP |= (pageResponse[5] & 0x04) == 0x04; + decoded.ORDSUP |= (pageResponse[5] & 0x02) == 0x02; + decoded.SIMPSUP |= (pageResponse[5] & 0x01) == 0x01; + decoded.WU_SUP |= (pageResponse[6] & 0x08) == 0x08; + decoded.CRD_SUP |= (pageResponse[6] & 0x04) == 0x04; + decoded.NV_SUP |= (pageResponse[6] & 0x02) == 0x02; + decoded.V_SUP |= (pageResponse[6] & 0x01) == 0x01; + decoded.NO_PI_CHK |= (pageResponse[7] & 0x20) == 0x20; + decoded.P_I_I_SUP |= (pageResponse[7] & 0x10) == 0x10; + decoded.LUICLR |= (pageResponse[7] & 0x01) == 0x01; + decoded.R_SUP |= (pageResponse[8] & 0x10) == 0x10; + decoded.HSSRELEF |= (pageResponse[8] & 0x02) == 0x02; + decoded.CBCS |= (pageResponse[8] & 0x01) == 0x01; + decoded.Nexus = (byte)(pageResponse[9] & 0x0F); + decoded.ExtendedTestMinutes = (ushort)((pageResponse[10] << 8) + pageResponse[11]); + decoded.POA_SUP |= (pageResponse[12] & 0x80) == 0x80; + decoded.HRA_SUP |= (pageResponse[12] & 0x40) == 0x40; + decoded.VSA_SUP |= (pageResponse[12] & 0x20) == 0x20; + decoded.MaximumSenseLength = pageResponse[13]; + + return decoded; + } + + public static string PrettifyPage_86(byte[] pageResponse) + { + return PrettifyPage_86(DecodePage_86(pageResponse)); + } + + public static string PrettifyPage_86(Page_86? modePage) + { + if(!modePage.HasValue) + return null; + + Page_86 page = modePage.Value; + StringBuilder sb = new StringBuilder(); + + sb.AppendLine("SCSI Extended INQUIRY Data:"); + + if(page.PeripheralDeviceType == PeripheralDeviceTypes.DirectAccess || + page.PeripheralDeviceType == PeripheralDeviceTypes.SCSIZonedBlockDEvice) + { + switch(page.SPT) + { + case 0: + sb.AppendLine("Logical unit supports type 1 protection"); + break; + case 1: + sb.AppendLine("Logical unit supports types 1 and 2 protection"); + break; + case 2: + sb.AppendLine("Logical unit supports type 2 protection"); + break; + case 3: + sb.AppendLine("Logical unit supports types 1 and 3 protection"); + break; + case 4: + sb.AppendLine("Logical unit supports type 3 protection"); + break; + case 5: + sb.AppendLine("Logical unit supports types 2 and 3 protection"); + break; + case 7: + sb.AppendLine("Logical unit supports types 1, 2 and 3 protection"); + break; + default: + sb.AppendFormat("Logical unit supports unknown protection defined by code {0}", (byte)page.SPT).AppendLine(); + break; + } + } + else if(page.PeripheralDeviceType == PeripheralDeviceTypes.SequentialAccess && page.SPT == 1) + sb.AppendLine("Logical unit supports logical block protection"); + + if(page.GRD_CHK) + sb.AppendLine("Device checks the logical block guard"); + if(page.APP_CHK) + sb.AppendLine("Device checks the logical block application tag"); + if(page.REF_CHK) + sb.AppendLine("Device checks the logical block reference tag"); + if(page.UASK_SUP) + sb.AppendLine("Device supports unit attention condition sense key specific data"); + if(page.GROUP_SUP) + sb.AppendLine("Device supports grouping"); + if(page.PRIOR_SUP) + sb.AppendLine("Device supports priority"); + if(page.HEADSUP) + sb.AppendLine("Device supports head of queue"); + if(page.ORDSUP) + sb.AppendLine("Device supports the ORDERED task attribute"); + if(page.SIMPSUP) + sb.AppendLine("Device supports the SIMPLE task attribute"); + if(page.WU_SUP) + sb.AppendLine("Device supports marking a block as uncorrectable with WRITE LONG"); + if(page.CRD_SUP) + sb.AppendLine("Device supports disabling correction with WRITE LONG"); + if(page.NV_SUP) + sb.AppendLine("Device has a non-volatile cache"); + if(page.V_SUP) + sb.AppendLine("Device has a volatile cache"); + if(page.NO_PI_CHK) + sb.AppendLine("Device has disabled protection information checks"); + if(page.P_I_I_SUP) + sb.AppendLine("Device supports protection information intervals"); + if(page.LUICLR) + sb.AppendLine("Device clears any unit attention condition in all LUNs after reporting for any LUN"); + if(page.R_SUP) + sb.AppendLine("Device supports referrals"); + if(page.HSSRELEF) + sb.AppendLine("Devoce implements alternate reset handling"); + if(page.CBCS) + sb.AppendLine("Device supports capability-based command security"); + if(page.POA_SUP) + sb.AppendLine("Device supports power-on activation for new microcode"); + if(page.HRA_SUP) + sb.AppendLine("Device supports hard reset activation for new microcode"); + if(page.VSA_SUP) + sb.AppendLine("Device supports vendor specific activation for new microcode"); + + if(page.ExtendedTestMinutes > 0) + sb.AppendFormat("Extended self-test takes {0} to complete", TimeSpan.FromMinutes(page.ExtendedTestMinutes)).AppendLine(); + + if(page.MaximumSenseLength > 0) + sb.AppendFormat("Device supports a maximum of {0} bytes for sense data", page.MaximumSenseLength).AppendLine(); + + return sb.ToString(); + } + + #endregion EVPD Page 0x86: Extended INQUIRY data page + + #region EVPD Page 0x89: ATA Information page + + /// + /// ATA Information page + /// Page code 0x89 + /// + public struct Page_89 + { + /// + /// The peripheral qualifier. + /// + public PeripheralQualifiers PeripheralQualifier; + /// + /// The type of the peripheral device. + /// + public PeripheralDeviceTypes PeripheralDeviceType; + /// + /// The page code. + /// + public byte PageCode; + /// + /// The length of the page. + /// + public ushort PageLength; + /// + /// Contains the SAT vendor identification + /// + public byte[] VendorIdentification; + /// + /// Contains the SAT product identification + /// + public byte[] ProductIdentification; + /// + /// Contains the SAT revision level + /// + public byte[] ProductRevisionLevel; + /// + /// Contains the ATA device signature + /// + public byte[] Signature; + /// + /// Contains the command code used to identify the device + /// + public byte CommandCode; + /// + /// Contains the response to ATA IDENTIFY (PACKET) DEVICE + /// + public byte[] IdentifyData; + } + + public static Page_89? DecodePage_89(byte[] pageResponse) + { + if(pageResponse == null) + return null; + + if(pageResponse[1] != 0x89) + return null; + + if((pageResponse[2] << 4) + pageResponse[3] + 4 != pageResponse.Length) + return null; + + if(pageResponse.Length < 572) + return null; + + Page_89 decoded = new Page_89(); + + decoded.PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5); + decoded.PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F); + decoded.PageLength = (ushort)((pageResponse[2] << 4) + pageResponse[3] + 4); + + decoded.VendorIdentification = new byte[8]; + decoded.ProductIdentification = new byte[16]; + decoded.ProductRevisionLevel = new byte[4]; + decoded.Signature = new byte[20]; + decoded.IdentifyData = new byte[512]; + + Array.Copy(pageResponse, 8, decoded.VendorIdentification, 0, 8); + Array.Copy(pageResponse, 8, decoded.ProductIdentification, 0, 16); + Array.Copy(pageResponse, 8, decoded.ProductRevisionLevel, 0, 4); + Array.Copy(pageResponse, 8, decoded.Signature, 0, 20); + decoded.CommandCode = pageResponse[56]; + Array.Copy(pageResponse, 8, decoded.IdentifyData, 0, 512); + + return decoded; + } + + public static string PrettifyPage_89(byte[] pageResponse) + { + return PrettifyPage_89(DecodePage_89(pageResponse)); + } + + // TODO: Decode ATA signature? + public static string PrettifyPage_89(Page_89? modePage) + { + if(!modePage.HasValue) + return null; + + Page_89 page = modePage.Value; + StringBuilder sb = new StringBuilder(); + + sb.AppendLine("SCSI to ATA Translation Layer Data:"); + + sb.AppendFormat("\tTranslation layer vendor: {0}", VendorString.Prettify(StringHandlers.CToString(page.VendorIdentification).Trim())).AppendLine(); + sb.AppendFormat("\tTranslation layer name: {0}", StringHandlers.CToString(page.ProductIdentification).Trim()).AppendLine(); + sb.AppendFormat("\tTranslation layer release level: {0}", StringHandlers.CToString(page.ProductRevisionLevel).Trim()).AppendLine(); + switch(page.CommandCode) + { + case 0xEC: + sb.AppendLine("\tDevice responded to ATA IDENTIFY DEVICE command."); + break; + case 0xA1: + sb.AppendLine("\tDevice responded to ATA IDENTIFY PACKET DEVICE command."); + break; + default: + sb.AppendFormat("\tDevice responded to ATA command {0:X2}h", page.CommandCode).AppendLine(); + break; + } + switch(page.Signature[0]) + { + case 0x00: + sb.AppendLine("\tDevice uses Parallel ATA."); + break; + case 0x34: + sb.AppendLine("\tDevice uses Serial ATA."); + break; + default: + sb.AppendFormat("\tDevice uses unknown transport with code {0}", page.Signature[0]).AppendLine(); + break; + } + + ATA.Identify.IdentifyDevice? id = ATA.Identify.Decode(page.IdentifyData); + if(id.HasValue) + { + sb.AppendLine("\tATA IDENTIFY information follows:"); + sb.AppendFormat("{0}", ATA.Identify.Prettify(id)).AppendLine(); + } + else + sb.AppendLine("\tCould not decode ATA IDENTIFY information"); + + return sb.ToString(); + } + + #endregion EVPD Page 0x89: ATA Information page + } } diff --git a/DiscImageChef/ChangeLog b/DiscImageChef/ChangeLog index 22bf6bc8c..856832b8e 100644 --- a/DiscImageChef/ChangeLog +++ b/DiscImageChef/ChangeLog @@ -1,3 +1,8 @@ +2016-10-13 Natalia Portillo + + * Commands/DeviceInfo.cs: + Added EVPD page 89h, SCSI to ATA translation layer + 2016-10-13 Natalia Portillo * Commands/DeviceInfo.cs: diff --git a/DiscImageChef/Commands/DeviceInfo.cs b/DiscImageChef/Commands/DeviceInfo.cs index d2c6eea8b..e300cff9d 100644 --- a/DiscImageChef/Commands/DeviceInfo.cs +++ b/DiscImageChef/Commands/DeviceInfo.cs @@ -283,6 +283,24 @@ namespace DiscImageChef.Commands doWriteFile(options.OutputPrefix, string.Format("_scsi_evpd_{0:X2}h.bin", page), string.Format("SCSI INQUIRY EVPD {0:X2}h", page), inqBuf); } } + else if(page == 0x86) + { + sense = dev.ScsiInquiry(out inqBuf, out senseBuf, page); + if(!sense) + { + DicConsole.WriteLine("{0}", Decoders.SCSI.EVPD.PrettifyPage_86(inqBuf)); + doWriteFile(options.OutputPrefix, string.Format("_scsi_evpd_{0:X2}h.bin", page), string.Format("SCSI INQUIRY EVPD {0:X2}h", page), inqBuf); + } + } + else if(page == 0x89) + { + sense = dev.ScsiInquiry(out inqBuf, out senseBuf, page); + if(!sense) + { + DicConsole.WriteLine("{0}", Decoders.SCSI.EVPD.PrettifyPage_89(inqBuf)); + doWriteFile(options.OutputPrefix, string.Format("_scsi_evpd_{0:X2}h.bin", page), string.Format("SCSI INQUIRY EVPD {0:X2}h", page), inqBuf); + } + } else { if(page != 0x00)