Added HP vendor EVPD, MODE pages and INQUIRY fields.

This commit is contained in:
2016-10-14 02:20:00 +01:00
parent d7746415b1
commit 895b1b51f8
6 changed files with 573 additions and 4 deletions

View File

@@ -1,3 +1,10 @@
2016-10-14 Natalia Portillo <claunia@claunia.com>
* EVPD.cs:
* Modes.cs:
* Inquiry.cs: Added HP vendor EVPD, MODE pages and INQUIRY
fields.
2016-10-14 Natalia Portillo <claunia@claunia.com>
* EVPD.cs: Added EVPD pages B1h, B2h, B3h and B4h.

View File

@@ -35,6 +35,7 @@ using System.Collections.Generic;
using System.Text;
using System.Security.Policy;
using System.Linq;
using System.Text.RegularExpressions;
namespace DiscImageChef.Decoders.SCSI
{
@@ -2256,7 +2257,7 @@ namespace DiscImageChef.Decoders.SCSI
return StringHandlers.CToString(ascii).Trim();
}
#region EVPD Page 0xB3: Automation Device Serial Number page
#endregion EVPD Page 0xB3: Automation Device Serial Number page
#region EVPD Page 0xB4: Data Transfer Device Element Address page
@@ -2280,6 +2281,174 @@ namespace DiscImageChef.Decoders.SCSI
}
#endregion EVPD Page 0xB4: Data Transfer Device Element Address page
#region EVPD Pages 0xC0 to 0xC5 (HP): Drive component revision level pages
/// <summary>
/// Drive component revision level pages
/// Page codes 0xC0 to 0xC5 (HP)
/// </summary>
public struct Page_C0_to_C5_HP
{
/// <summary>
/// The peripheral qualifier.
/// </summary>
public PeripheralQualifiers PeripheralQualifier;
/// <summary>
/// The type of the peripheral device.
/// </summary>
public PeripheralDeviceTypes PeripheralDeviceType;
/// <summary>
/// The page code.
/// </summary>
public byte PageCode;
/// <summary>
/// The length of the page.
/// </summary>
public byte PageLength;
public byte[] Component;
public byte[] Version;
public byte[] Date;
public byte[] Variant;
public byte[] Copyright;
}
public static Page_C0_to_C5_HP? DecodePage_C0_to_C5_HP(byte[] pageResponse)
{
if(pageResponse == null)
return null;
if(pageResponse[1] != 0xC0 && pageResponse[1] != 0xC1 &&
pageResponse[1] != 0xC2 && pageResponse[1] != 0xC3 &&
pageResponse[1] != 0xC4 && pageResponse[1] != 0xC5)
return null;
if(pageResponse.Length < 4)
return null;
Page_C0_to_C5_HP decoded = new Page_C0_to_C5_HP();
decoded.PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5);
decoded.PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F);
decoded.PageLength = (byte)(pageResponse[3] + 4);
decoded.PageCode = pageResponse[1];
if(pageResponse[3] == 92 && pageResponse.Length < 96)
{
decoded.Component = new byte[26];
decoded.Version = new byte[19];
decoded.Date = new byte[24];
decoded.Variant = new byte[23];
Array.Copy(pageResponse, 4, decoded.Component, 0, 26);
Array.Copy(pageResponse, 30, decoded.Version, 0, 19);
Array.Copy(pageResponse, 49, decoded.Date, 0, 24);
Array.Copy(pageResponse, 73, decoded.Variant, 0, 23);
return decoded;
}
if(pageResponse[4] == pageResponse[3] - 1)
{
List<byte> array = new List<byte>();
string fwRegExStr = "Firmware Rev\\s+=\\s+(?<fw>\\d+\\.\\d+)\\s+Build date\\s+=\\s+(?<date>(\\w|\\d|\\s*.)*)\\s*$";
string fwcRegExStr = "FW_CONF\\s+=\\s+(?<value>0x[0-9A-Fa-f]{8})\\s*$";
string servoRegExStr = "Servo\\s+Rev\\s+=\\s+(?<version>\\d+\\.\\d+)\\s*$";
Regex fwRegEx = new Regex(fwRegExStr);
Regex fwcRegEx = new Regex(fwcRegExStr);
Regex servoRegEx = new Regex(servoRegExStr);
Match fwMatch;
Match fwcMatch;
Match servoMatch;
for(int pos = 5; pos < pageResponse.Length; pos++)
{
if(pageResponse[pos] == 0x00)
{
string str = StringHandlers.CToString(array.ToArray());
fwMatch = fwRegEx.Match(str);
fwcMatch = fwcRegEx.Match(str);
servoMatch = servoRegEx.Match(str);
if(str.ToLowerInvariant().StartsWith("copyright", StringComparison.Ordinal))
decoded.Copyright = Encoding.ASCII.GetBytes(str);
else if(fwMatch.Success)
{
decoded.Component = Encoding.ASCII.GetBytes("Firmware");
decoded.Version = Encoding.ASCII.GetBytes(fwMatch.Groups["fw"].Value);
decoded.Date = Encoding.ASCII.GetBytes(fwMatch.Groups["date"].Value);
}
else if(fwcMatch.Success)
decoded.Variant = Encoding.ASCII.GetBytes(fwMatch.Groups["value"].Value);
else if(servoMatch.Success)
{
decoded.Component = Encoding.ASCII.GetBytes("Servo");
decoded.Version = Encoding.ASCII.GetBytes(servoMatch.Groups["version"].Value);
}
array = new List<byte>();
}
else
array.Add(pageResponse[pos]);
}
return decoded;
}
return null;
}
public static string PrettifyPage_C0_to_C5_HP(byte[] pageResponse)
{
return PrettifyPage_C0_to_C5_HP(DecodePage_C0_to_C5_HP(pageResponse));
}
public static string PrettifyPage_C0_to_C5_HP(Page_C0_to_C5_HP? modePage)
{
if(!modePage.HasValue)
return null;
Page_C0_to_C5_HP page = modePage.Value;
StringBuilder sb = new StringBuilder();
switch(page.PageCode)
{
case 0xC0:
sb.AppendLine("HP Drive Firmware Revision Levels page:");
break;
case 0xC1:
sb.AppendLine("HP Drive Hardware Revision Levels page:");
break;
case 0xC2:
sb.AppendLine("HP Drive PCA Revision Levels page:");
break;
case 0xC3:
sb.AppendLine("HP Drive Mechanism Revision Levels page:");
break;
case 0xC4:
sb.AppendLine("HP Drive Head Assembly Revision Levels page:");
break;
case 0xC5:
sb.AppendLine("HP Drive ACI Revision Levels page:");
break;
}
if(page.Component != null && page.Component.Length > 0)
sb.AppendFormat("\tComponent: {0}", StringHandlers.CToString(page.Component)).AppendLine();
if(page.Version != null && page.Version.Length > 0)
sb.AppendFormat("\tVersion: {0}", StringHandlers.CToString(page.Version)).AppendLine();
if(page.Date != null && page.Date.Length > 0)
sb.AppendFormat("\tDate: {0}", StringHandlers.CToString(page.Date)).AppendLine();
if(page.Variant != null && page.Variant.Length > 0)
sb.AppendFormat("\tVariant: {0}", StringHandlers.CToString(page.Variant)).AppendLine();
if(page.Copyright != null && page.Copyright.Length > 0)
sb.AppendFormat("\tCopyright: {0}", StringHandlers.CToString(page.Copyright)).AppendLine();
return sb.ToString();
}
#endregion EVPD Pages 0xC0 to 0xC5 (HP): Drive component revision level pages
}
}

View File

@@ -33,6 +33,7 @@
using System;
using System.Text;
using DiscImageChef.Console;
using System.Linq;
namespace DiscImageChef.Decoders.SCSI
{
@@ -142,6 +143,15 @@ namespace DiscImageChef.Decoders.SCSI
decoded.ProductRevisionLevel = new byte[4];
Array.Copy(SCSIInquiryResponse, 32, decoded.ProductRevisionLevel, 0, 4);
}
if(SCSIInquiryResponse.Length >= 49)
{
// HP
decoded.HPPresent = true;
decoded.HP_WORM |= (SCSIInquiryResponse[40] & 0x01) == 0x01;
decoded.HP_WORMVersion = (byte)((SCSIInquiryResponse[40] & 0x7F) >> 1);
decoded.HP_OBDR = new byte[6];
Array.Copy(SCSIInquiryResponse, 43, decoded.HP_OBDR, 0, 6);
}
if(SCSIInquiryResponse.Length >= 56)
{
decoded.VendorSpecific = new byte[20];
@@ -1896,7 +1906,7 @@ namespace DiscImageChef.Decoders.SCSI
}
#region Quantum vendor prettifying
if(response.QuantumPresent && StringHandlers.CToString(response.VendorIdentification).ToLowerInvariant() == "quantum")
if(response.QuantumPresent && StringHandlers.CToString(response.VendorIdentification).ToLowerInvariant().Trim() == "quantum")
{
sb.AppendLine("Quantum vendor-specific information:");
switch(response.Qt_ProductFamily)
@@ -1945,7 +1955,7 @@ namespace DiscImageChef.Decoders.SCSI
#endregion Quantum vendor prettifying
#region IBM vendor prettifying
if(response.IBMPresent && StringHandlers.CToString(response.VendorIdentification).ToLowerInvariant() == "ibm")
if(response.IBMPresent && StringHandlers.CToString(response.VendorIdentification).ToLowerInvariant().Trim() == "ibm")
{
sb.AppendLine("IBM vendor-specific information:");
@@ -1961,6 +1971,20 @@ namespace DiscImageChef.Decoders.SCSI
}
#endregion IBM vendor prettifying
#region HP vendor prettifying
if(response.HPPresent && StringHandlers.CToString(response.VendorIdentification).ToLowerInvariant().Trim() == "hp")
{
sb.AppendLine("HP vendor-specific information:");
if(response.HP_WORM)
sb.AppendFormat("Device supports WORM version {0}", response.HP_WORMVersion).AppendLine();
byte[] OBDRSign = { 0x24, 0x44, 0x52, 0x2D, 0x31, 0x30};
if(OBDRSign.SequenceEqual(response.HP_OBDR))
sb.AppendLine("Device supports Tape Disaster Recovery");
}
#endregion HP vendor prettifying
#if DEBUG
if(response.DeviceTypeModifier != 0)
sb.AppendFormat("Vendor's device type modifier = 0x{0:X2}", response.DeviceTypeModifier).AppendLine();
@@ -2365,6 +2389,27 @@ namespace DiscImageChef.Decoders.SCSI
/// </summary>
public byte IBM_OEMSpecific;
#endregion IBM vendor unique inquiry data structure
#region HP vendor unique inquiry data structure
/// <summary>
/// Means that the INQUIRY response contains 49 bytes or more, so this data has been filled
/// </summary>
public bool HPPresent;
/// <summary>
/// WORM version
/// Byte 40 bits 7 to 1
/// </summary>
public byte HP_WORMVersion;
/// <summary>
/// WORM supported
/// Byte 40 bit 0
/// </summary>
public bool HP_WORM;
/// <summary>
/// Bytes 43 to 48
/// </summary>
public byte[] HP_OBDR;
#endregion HP vendor unique inquiry data structure
}
#endregion Public structures

View File

@@ -7768,7 +7768,318 @@ namespace DiscImageChef.Decoders.SCSI
return sb.ToString();
}
#endregion IBM Mode Page 0x24: Drive Capabilities Control Mode page
#endregion IBM Mode Page 0x3D: Behaviour Configuration Mode page
#region HP Mode Page 0x3B: Serial Number Override Mode page
public struct HP_ModePage_3B
{
/// <summary>
/// Parameters can be saved
/// </summary>
public bool PS;
public byte MSN;
public byte[] SerialNumber;
}
public static HP_ModePage_3B? DecodeHPModePage_3B(byte[] pageResponse)
{
if(pageResponse == null)
return null;
if((pageResponse[0] & 0x40) == 0x40)
return null;
if((pageResponse[0] & 0x3F) != 0x3B)
return null;
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
if(pageResponse.Length != 16)
return null;
HP_ModePage_3B decoded = new HP_ModePage_3B();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.MSN = (byte)(pageResponse[2] & 0x03);
decoded.SerialNumber = new byte[10];
Array.Copy(pageResponse, 6, decoded.SerialNumber, 0, 10);
return decoded;
}
public static string PrettifyHPModePage_3B(byte[] pageResponse)
{
return PrettifyHPModePage_3B(DecodeHPModePage_3B(pageResponse));
}
public static string PrettifyHPModePage_3B(HP_ModePage_3B? modePage)
{
if(!modePage.HasValue)
return null;
HP_ModePage_3B page = modePage.Value;
StringBuilder sb = new StringBuilder();
sb.AppendLine("HP Serial Number Override Mode Page:");
if(page.PS)
sb.AppendLine("\tParameters can be saved");
switch(page.MSN)
{
case 1:
sb.AppendLine("\tSerial number is the manufacturer's default value");
break;
case 3:
sb.AppendLine("\tSerial number is not the manufacturer's default value");
break;
}
sb.AppendFormat("\tSerial number: {0}", StringHandlers.CToString(page.SerialNumber)).AppendLine();
return sb.ToString();
}
#endregion HP Mode Page 0x3B: Serial Number Override Mode page
#region HP Mode Page 0x3C: Device Time Mode page
public struct HP_ModePage_3C
{
/// <summary>
/// Parameters can be saved
/// </summary>
public bool PS;
public bool LT;
public bool WT;
public bool PT;
public ushort CurrentPowerOn;
public uint PowerOnTime;
public bool UTC;
public bool NTP;
public uint WorldTime;
public byte LibraryHours;
public byte LibraryMinutes;
public byte LibrarySeconds;
public uint CumulativePowerOn;
}
public static HP_ModePage_3C? DecodeHPModePage_3C(byte[] pageResponse)
{
if(pageResponse == null)
return null;
if((pageResponse[0] & 0x40) == 0x40)
return null;
if((pageResponse[0] & 0x3F) != 0x3C)
return null;
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
if(pageResponse.Length != 36)
return null;
HP_ModePage_3C decoded = new HP_ModePage_3C();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.LT |= (pageResponse[2] & 0x04) == 0x04;
decoded.WT |= (pageResponse[2] & 0x02) == 0x02;
decoded.PT |= (pageResponse[2] & 0x01) == 0x01;
decoded.CurrentPowerOn = (ushort)((pageResponse[6] << 8) + pageResponse[7]);
decoded.PowerOnTime = (uint)((pageResponse[8] << 24) + (pageResponse[9] << 16) + (pageResponse[10] << 8) + pageResponse[11]);
decoded.UTC |= (pageResponse[14] & 0x02) == 0x02;
decoded.NTP |= (pageResponse[14] & 0x01) == 0x01;
decoded.WorldTime = (uint)((pageResponse[16] << 24) + (pageResponse[17] << 16) + (pageResponse[18] << 8) + pageResponse[19]);
decoded.LibraryHours = pageResponse[23];
decoded.LibraryMinutes = pageResponse[24];
decoded.LibrarySeconds = pageResponse[25];
decoded.CumulativePowerOn = (uint)((pageResponse[32] << 24) + (pageResponse[33] << 16) + (pageResponse[34] << 8) + pageResponse[35]);
return decoded;
}
public static string PrettifyHPModePage_3C(byte[] pageResponse)
{
return PrettifyHPModePage_3C(DecodeHPModePage_3C(pageResponse));
}
public static string PrettifyHPModePage_3C(HP_ModePage_3C? modePage)
{
if(!modePage.HasValue)
return null;
HP_ModePage_3C page = modePage.Value;
StringBuilder sb = new StringBuilder();
sb.AppendLine("HP Device Time Mode Page:");
if(page.PS)
sb.AppendLine("\tParameters can be saved");
if(page.PT)
{
sb.AppendFormat("\tDrive has been powered up {0} times", page.CurrentPowerOn);
sb.AppendFormat("\tDrive has been powered up since {0} this time", TimeSpan.FromSeconds(page.PowerOnTime)).AppendLine();
sb.AppendFormat("\tDrive has been powered up a total of {0}", TimeSpan.FromSeconds(page.CumulativePowerOn)).AppendLine();
}
if(page.WT)
{
sb.AppendFormat("\tDrive's date/time is: {0}", DateHandlers.UNIXUnsignedToDateTime(page.WorldTime)).AppendLine();
if(page.UTC)
sb.AppendLine("\tDrive's time is UTC");
if(page.NTP)
sb.AppendLine("\tDrive's time is synchronized with a NTP source");
}
if(page.LT)
sb.AppendFormat("\tLibrary time is {0}", new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, page.LibraryHours, page.LibraryMinutes, page.LibrarySeconds)).AppendLine();
return sb.ToString();
}
#endregion HP Mode Page 0x3C: Device Time Mode page
#region HP Mode Page 0x3D: Extended Reset Mode page
public struct HP_ModePage_3D
{
/// <summary>
/// Parameters can be saved
/// </summary>
public bool PS;
public byte ResetBehaviour;
}
public static HP_ModePage_3D? DecodeHPModePage_3D(byte[] pageResponse)
{
if(pageResponse == null)
return null;
if((pageResponse[0] & 0x40) == 0x40)
return null;
if((pageResponse[0] & 0x3F) != 0x3D)
return null;
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
if(pageResponse.Length != 4)
return null;
HP_ModePage_3D decoded = new HP_ModePage_3D();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.ResetBehaviour = (byte)(pageResponse[2] & 0x03);
return decoded;
}
public static string PrettifyHPModePage_3D(byte[] pageResponse)
{
return PrettifyHPModePage_3D(DecodeHPModePage_3D(pageResponse));
}
public static string PrettifyHPModePage_3D(HP_ModePage_3D? modePage)
{
if(!modePage.HasValue)
return null;
HP_ModePage_3D page = modePage.Value;
StringBuilder sb = new StringBuilder();
sb.AppendLine("HP Extended Reset Mode Page:");
if(page.PS)
sb.AppendLine("\tParameters can be saved");
switch(page.ResetBehaviour)
{
case 0:
sb.AppendLine("\tNormal reset behaviour");
break;
case 1:
sb.AppendLine("\tDrive will flush and position itself on a LUN or target reset");
break;
case 2:
sb.AppendLine("\tDrive will maintain position on a LUN or target reset");
break;
}
return sb.ToString();
}
#endregion HP Mode Page 0x3D: Extended Reset Mode page
#region HP Mode Page 0x3E: CD-ROM Emulation/Disaster Recovery Mode page
public struct HP_ModePage_3E
{
/// <summary>
/// Parameters can be saved
/// </summary>
public bool PS;
public bool NonAuto;
public bool CDmode;
}
public static HP_ModePage_3E? DecodeHPModePage_3E(byte[] pageResponse)
{
if(pageResponse == null)
return null;
if((pageResponse[0] & 0x40) == 0x40)
return null;
if((pageResponse[0] & 0x3F) != 0x3E)
return null;
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
if(pageResponse.Length != 4)
return null;
HP_ModePage_3E decoded = new HP_ModePage_3E();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.NonAuto |= (pageResponse[2] & 0x02) == 0x02;
decoded.CDmode|= (pageResponse[2] & 0x01) == 0x01;
return decoded;
}
public static string PrettifyHPModePage_3E(byte[] pageResponse)
{
return PrettifyHPModePage_3E(DecodeHPModePage_3E(pageResponse));
}
public static string PrettifyHPModePage_3E(HP_ModePage_3E? modePage)
{
if(!modePage.HasValue)
return null;
HP_ModePage_3E page = modePage.Value;
StringBuilder sb = new StringBuilder();
sb.AppendLine("HP CD-ROM Emulation/Disaster Recovery Mode Page:");
if(page.PS)
sb.AppendLine("\tParameters can be saved");
if(page.CDmode)
sb.AppendLine("\tDrive is emulating a CD-ROM drive");
else
sb.AppendLine("\tDrive is not emulating a CD-ROM drive");
if(page.NonAuto)
sb.AppendLine("\tDrive will not exit emulation automatically");
return sb.ToString();
}
#endregion HP Mode Page 0x3E: CD-ROM Emulation/Disaster Recovery Mode page
}
}

View File

@@ -1,3 +1,8 @@
2016-10-14 Natalia Portillo <claunia@claunia.com>
* Commands/DeviceInfo.cs:
Added HP vendor EVPD, MODE pages and INQUIRY fields.
2016-10-14 Natalia Portillo <claunia@claunia.com>
* Commands/DeviceInfo.cs:

View File

@@ -392,6 +392,16 @@ 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 == 0xC0 || page == 0xC1 || page == 0xC2 || page == 0xC3 || page == 0xC4 || page == 0xC5) &&
StringHandlers.CToString(inq.Value.VendorIdentification).ToLowerInvariant().Trim() == "hp")
{
sense = dev.ScsiInquiry(out inqBuf, out senseBuf, page);
if(!sense)
{
DicConsole.WriteLine("{0}", Decoders.SCSI.EVPD.PrettifyPage_C0_to_C5_HP(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 == 0xDF && StringHandlers.CToString(inq.Value.VendorIdentification).ToLowerInvariant().Trim() == "certance")
{
sense = dev.ScsiInquiry(out inqBuf, out senseBuf, page);
@@ -720,12 +730,32 @@ namespace DiscImageChef.Commands
else
goto default;
break;
}
case 0x3B:
{
if(StringHandlers.CToString(inq.Value.VendorIdentification).Trim() == "HP")
DicConsole.WriteLine(Decoders.SCSI.Modes.PrettifyHPModePage_3B(page.PageResponse));
else
goto default;
break;
}
case 0x3C:
{
if(StringHandlers.CToString(inq.Value.VendorIdentification).Trim() == "HP")
DicConsole.WriteLine(Decoders.SCSI.Modes.PrettifyHPModePage_3C(page.PageResponse));
else
goto default;
break;
}
case 0x3D:
{
if(StringHandlers.CToString(inq.Value.VendorIdentification).Trim() == "IBM")
DicConsole.WriteLine(Decoders.SCSI.Modes.PrettifyIBMModePage_3D(page.PageResponse));
else if(StringHandlers.CToString(inq.Value.VendorIdentification).Trim() == "HP")
DicConsole.WriteLine(Decoders.SCSI.Modes.PrettifyHPModePage_3D(page.PageResponse));
else
goto default;
@@ -735,6 +765,8 @@ namespace DiscImageChef.Commands
{
if(StringHandlers.CToString(inq.Value.VendorIdentification).Trim() == "FUJITSU")
DicConsole.WriteLine(Decoders.SCSI.Modes.PrettifyFujitsuModePage_3E(page.PageResponse));
else if(StringHandlers.CToString(inq.Value.VendorIdentification).Trim() == "HP")
DicConsole.WriteLine(Decoders.SCSI.Modes.PrettifyHPModePage_3E(page.PageResponse));
else
goto default;