public DeviceInfo(Device dev) { Type = dev.Type; Manufacturer = dev.Manufacturer; Model = dev.Model; Revision = dev.Revision; Serial = dev.Serial; ScsiType = dev.ScsiType; IsRemovable = dev.IsRemovable; IsUsb = dev.IsUsb; UsbVendorId = dev.UsbVendorId; UsbProductId = dev.UsbProductId; UsbDescriptors = dev.UsbDescriptors; UsbManufacturerString = dev.UsbManufacturerString; UsbProductString = dev.UsbProductString; UsbSerialString = dev.UsbSerialString; IsFireWire = dev.IsFireWire; FireWireGuid = dev.FireWireGuid; FireWireModel = dev.FireWireModel; FireWireModelName = dev.FireWireModelName; FireWireVendor = dev.FireWireVendor; FireWireVendorName = dev.FireWireVendorName; IsCompactFlash = dev.IsCompactFlash; IsPcmcia = dev.IsPcmcia; Cis = dev.Cis; switch (dev.Type) { case DeviceType.ATA: { bool sense = dev.AtaIdentify(out byte[] ataBuf, out AtaErrorRegistersChs errorRegisters); if (sense) { DicConsole.DebugWriteLine("Device-Info command", "STATUS = 0x{0:X2}", errorRegisters.Status); DicConsole.DebugWriteLine("Device-Info command", "ERROR = 0x{0:X2}", errorRegisters.Error); DicConsole.DebugWriteLine("Device-Info command", "NSECTOR = 0x{0:X2}", errorRegisters.SectorCount); DicConsole.DebugWriteLine("Device-Info command", "SECTOR = 0x{0:X2}", errorRegisters.Sector); DicConsole.DebugWriteLine("Device-Info command", "CYLHIGH = 0x{0:X2}", errorRegisters.CylinderHigh); DicConsole.DebugWriteLine("Device-Info command", "CYLLOW = 0x{0:X2}", errorRegisters.CylinderLow); DicConsole.DebugWriteLine("Device-Info command", "DEVICE = 0x{0:X2}", errorRegisters.DeviceHead); DicConsole.DebugWriteLine("Device-Info command", "Error code = {0}", dev.LastError); break; } if (dev.Error) { DicConsole.ErrorWriteLine("Error {0} querying ATA IDENTIFY", dev.LastError); break; } AtaIdentify = ataBuf; dev.EnableMediaCardPassThrough(out errorRegisters, dev.Timeout, out _); if (errorRegisters.Sector == 0xAA && errorRegisters.SectorCount == 0x55) { AtaMcptError = errorRegisters; } break; } case DeviceType.ATAPI: { bool sense = dev.AtapiIdentify(out byte[] ataBuf, out AtaErrorRegistersChs errorRegisters); if (sense) { DicConsole.DebugWriteLine("Device-Info command", "STATUS = 0x{0:X2}", errorRegisters.Status); DicConsole.DebugWriteLine("Device-Info command", "ERROR = 0x{0:X2}", errorRegisters.Error); DicConsole.DebugWriteLine("Device-Info command", "NSECTOR = 0x{0:X2}", errorRegisters.SectorCount); DicConsole.DebugWriteLine("Device-Info command", "SECTOR = 0x{0:X2}", errorRegisters.Sector); DicConsole.DebugWriteLine("Device-Info command", "CYLHIGH = 0x{0:X2}", errorRegisters.CylinderHigh); DicConsole.DebugWriteLine("Device-Info command", "CYLLOW = 0x{0:X2}", errorRegisters.CylinderLow); DicConsole.DebugWriteLine("Device-Info command", "DEVICE = 0x{0:X2}", errorRegisters.DeviceHead); DicConsole.DebugWriteLine("Device-Info command", "Error code = {0}", dev.LastError); break; } if (!dev.Error) { AtapiIdentify = ataBuf; } else { DicConsole.ErrorWriteLine("Error {0} querying ATA PACKET IDENTIFY", dev.LastError); } // ATAPI devices are also SCSI devices goto case DeviceType.SCSI; } case DeviceType.SCSI: { bool sense = dev.ScsiInquiry(out byte[] inqBuf, out byte[] senseBuf); if (sense) { DicConsole.ErrorWriteLine("SCSI error:\n{0}", Sense.PrettifySense(senseBuf)); break; } ScsiInquiryData = inqBuf; ScsiInquiry = Inquiry.Decode(inqBuf); sense = dev.ScsiInquiry(out inqBuf, out senseBuf, 0x00); if (!sense) { ScsiEvpdPages = new Dictionary <byte, byte[]>(); byte[] pages = EVPD.DecodePage00(inqBuf); if (pages != null) { foreach (byte page in pages) { sense = dev.ScsiInquiry(out inqBuf, out senseBuf, page); if (sense) { continue; } ScsiEvpdPages.Add(page, inqBuf); } } } PeripheralDeviceTypes devType = (PeripheralDeviceTypes)ScsiInquiry.Value.PeripheralDeviceType; sense = dev.ModeSense10(out byte[] modeBuf, out senseBuf, false, true, ScsiModeSensePageControl.Current, 0x3F, 0xFF, 5, out _); if (!sense && !dev.Error) { ScsiModeSense10 = modeBuf; } if (sense || dev.Error) { sense = dev.ModeSense10(out modeBuf, out senseBuf, false, true, ScsiModeSensePageControl.Current, 0x3F, 0x00, 5, out _); if (!sense && !dev.Error) { ScsiModeSense10 = modeBuf; } } if (!sense && !dev.Error) { ScsiMode = Modes.DecodeMode10(modeBuf, devType); } bool useMode10 = !(sense || dev.Error || !ScsiMode.HasValue); sense = dev.ModeSense6(out modeBuf, out senseBuf, false, ScsiModeSensePageControl.Current, 0x3F, 0xFF, 5, out _); if (!sense && !dev.Error) { ScsiModeSense6 = modeBuf; } if (sense || dev.Error) { sense = dev.ModeSense6(out modeBuf, out senseBuf, false, ScsiModeSensePageControl.Current, 0x3F, 0x00, 5, out _); if (!sense && !dev.Error) { ScsiModeSense6 = modeBuf; } } if (sense || dev.Error) { sense = dev.ModeSense(out modeBuf, out senseBuf, 5, out _); if (!sense && !dev.Error) { ScsiModeSense6 = modeBuf; } } if (!sense && !dev.Error && !useMode10) { ScsiMode = Modes.DecodeMode6(modeBuf, devType); } switch (devType) { case PeripheralDeviceTypes.MultiMediaDevice: { sense = dev.GetConfiguration(out byte[] confBuf, out senseBuf, dev.Timeout, out _); if (!sense) { MmcConfiguration = confBuf; } // TODO: DVD drives respond correctly to BD status. // While specification says if no medium is present // it should inform all possible capabilities, // testing drives show only supported media capabilities. /* * byte[] strBuf; * sense = dev.ReadDiscStructure(out strBuf, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.CapabilityList, 0, dev.Timeout, out _); * * if (!sense) * { * Decoders.SCSI.DiscStructureCapabilities.Capability[] caps = Decoders.SCSI.DiscStructureCapabilities.Decode(strBuf); * if (caps != null) * { * foreach (Decoders.SCSI.DiscStructureCapabilities.Capability cap in caps) * { * if (cap.SDS && cap.RDS) * DicConsole.WriteLine("Drive can READ/SEND DISC STRUCTURE format {0:X2}h", cap.FormatCode); * else if (cap.SDS) * DicConsole.WriteLine("Drive can SEND DISC STRUCTURE format {0:X2}h", cap.FormatCode); * else if (cap.RDS) * DicConsole.WriteLine("Drive can READ DISC STRUCTURE format {0:X2}h", cap.FormatCode); * } * } * } * * sense = dev.ReadDiscStructure(out strBuf, out senseBuf, MmcDiscStructureMediaType.BD, 0, 0, MmcDiscStructureFormat.CapabilityList, 0, dev.Timeout, out _); * * if (!sense) * { * Decoders.SCSI.DiscStructureCapabilities.Capability[] caps = Decoders.SCSI.DiscStructureCapabilities.Decode(strBuf); * if (caps != null) * { * foreach (Decoders.SCSI.DiscStructureCapabilities.Capability cap in caps) * { * if (cap.SDS && cap.RDS) * DicConsole.WriteLine("Drive can READ/SEND DISC STRUCTURE format {0:X2}h", cap.FormatCode); * else if (cap.SDS) * DicConsole.WriteLine("Drive can SEND DISC STRUCTURE format {0:X2}h", cap.FormatCode); * else if (cap.RDS) * DicConsole.WriteLine("Drive can READ DISC STRUCTURE format {0:X2}h", cap.FormatCode); * } * } * } */ #region Plextor if (dev.Manufacturer == "PLEXTOR") { bool plxtSense = true; bool plxtDvd = false; byte[] plxtBuf = null; switch (dev.Model) { case "DVDR PX-708A": case "DVDR PX-708A2": case "DVDR PX-712A": plxtDvd = true; plxtSense = dev.PlextorReadEeprom(out plxtBuf, out senseBuf, dev.Timeout, out _); break; case "DVDR PX-714A": case "DVDR PX-716A": case "DVDR PX-716AL": case "DVDR PX-755A": case "DVDR PX-760A": { plxtBuf = new byte[256 * 4]; for (byte i = 0; i < 4; i++) { plxtSense = dev.PlextorReadEepromBlock(out byte[] plxtBufSmall, out senseBuf, i, 256, dev.Timeout, out _); if (plxtSense) { break; } Array.Copy(plxtBufSmall, 0, plxtBuf, i * 256, 256); } plxtDvd = true; break; } default: { if (dev.Model.StartsWith("CD-R ", StringComparison.Ordinal)) { plxtSense = dev.PlextorReadEepromCdr(out plxtBuf, out senseBuf, dev.Timeout, out _); } break; } } PlextorFeatures = new Plextor { IsDvd = plxtDvd }; if (!plxtSense) { PlextorFeatures.Eeprom = plxtBuf; if (plxtDvd) { PlextorFeatures.Discs = BigEndianBitConverter.ToUInt16(plxtBuf, 0x0120); PlextorFeatures.CdReadTime = BigEndianBitConverter.ToUInt32(plxtBuf, 0x0122); PlextorFeatures.CdWriteTime = BigEndianBitConverter.ToUInt32(plxtBuf, 0x0126); PlextorFeatures.DvdReadTime = BigEndianBitConverter.ToUInt32(plxtBuf, 0x012A); PlextorFeatures.DvdWriteTime = BigEndianBitConverter.ToUInt32(plxtBuf, 0x012E); } else { PlextorFeatures.Discs = BigEndianBitConverter.ToUInt16(plxtBuf, 0x0078); PlextorFeatures.CdReadTime = BigEndianBitConverter.ToUInt32(plxtBuf, 0x006C); PlextorFeatures.CdWriteTime = BigEndianBitConverter.ToUInt32(plxtBuf, 0x007A); } } plxtSense = dev.PlextorGetPoweRec(out senseBuf, out bool plxtPwrRecEnabled, out ushort plxtPwrRecSpeed, dev.Timeout, out _); if (!plxtSense) { PlextorFeatures.PoweRec = true; if (plxtPwrRecEnabled) { PlextorFeatures.PoweRecEnabled = true; PlextorFeatures.PoweRecRecommendedSpeed = plxtPwrRecSpeed; plxtSense = dev.PlextorGetSpeeds(out senseBuf, out ushort plxtPwrRecSelected, out ushort plxtPwrRecMax, out ushort plxtPwrRecLast, dev.Timeout, out _); if (!plxtSense) { PlextorFeatures.PoweRecSelected = plxtPwrRecSelected; PlextorFeatures.PoweRecMax = plxtPwrRecMax; PlextorFeatures.PoweRecLast = plxtPwrRecLast; } } } // TODO: Check it with a drive plxtSense = dev.PlextorGetSilentMode(out plxtBuf, out senseBuf, dev.Timeout, out _); if (!plxtSense) { if (plxtBuf[0] == 1) { PlextorFeatures.SilentModeEnabled = true; PlextorFeatures.AccessTimeLimit = plxtBuf[1]; PlextorFeatures.CdReadSpeedLimit = plxtBuf[2]; PlextorFeatures.DvdReadSpeedLimit = plxtBuf[3]; PlextorFeatures.CdWriteSpeedLimit = plxtBuf[4]; // TODO: Check which one is each one /* * if(plxtBuf[6] > 0) * DicConsole.WriteLine("\tTray eject speed limited to {0}", * -(plxtBuf[6] + 48)); * if(plxtBuf[7] > 0) * DicConsole.WriteLine("\tTray eject speed limited to {0}", * plxtBuf[7] - 47); */ } } plxtSense = dev.PlextorGetGigaRec(out plxtBuf, out senseBuf, dev.Timeout, out _); if (!plxtSense) { PlextorFeatures.GigaRec = true; } plxtSense = dev.PlextorGetSecuRec(out plxtBuf, out senseBuf, dev.Timeout, out _); if (!plxtSense) { PlextorFeatures.SecuRec = true; } plxtSense = dev.PlextorGetSpeedRead(out plxtBuf, out senseBuf, dev.Timeout, out _); if (!plxtSense) { PlextorFeatures.SpeedRead = true; if ((plxtBuf[2] & 0x01) == 0x01) { PlextorFeatures.SpeedReadEnabled = true; } } plxtSense = dev.PlextorGetHiding(out plxtBuf, out senseBuf, dev.Timeout, out _); if (!plxtSense) { PlextorFeatures.Hiding = true; if ((plxtBuf[2] & 0x02) == 0x02) { PlextorFeatures.HidesRecordables = true; } if ((plxtBuf[2] & 0x01) == 0x01) { PlextorFeatures.HidesSessions = true; } } plxtSense = dev.PlextorGetVariRec(out plxtBuf, out senseBuf, false, dev.Timeout, out _); if (!plxtSense) { PlextorFeatures.VariRec = true; } if (plxtDvd) { plxtSense = dev.PlextorGetVariRec(out plxtBuf, out senseBuf, true, dev.Timeout, out _); if (!plxtSense) { PlextorFeatures.VariRecDvd = true; } plxtSense = dev.PlextorGetBitsetting(out plxtBuf, out senseBuf, false, dev.Timeout, out _); if (!plxtSense) { PlextorFeatures.BitSetting = true; } plxtSense = dev.PlextorGetBitsetting(out plxtBuf, out senseBuf, true, dev.Timeout, out _); if (!plxtSense) { PlextorFeatures.BitSettingDl = true; } plxtSense = dev.PlextorGetTestWriteDvdPlus(out plxtBuf, out senseBuf, dev.Timeout, out _); if (!plxtSense) { PlextorFeatures.DvdPlusWriteTest = true; } } } #endregion Plextor if (ScsiInquiry.Value.KreonPresent) { if (!dev.KreonGetFeatureList(out senseBuf, out KreonFeatures krFeatures, dev.Timeout, out _)) { KreonFeatures = krFeatures; } } break; } case PeripheralDeviceTypes.SequentialAccess: { sense = dev.ReadBlockLimits(out byte[] seqBuf, out senseBuf, dev.Timeout, out _); if (sense) { DicConsole.ErrorWriteLine("READ BLOCK LIMITS:\n{0}", Sense.PrettifySense(senseBuf)); } else { BlockLimits = seqBuf; } sense = dev.ReportDensitySupport(out seqBuf, out senseBuf, dev.Timeout, out _); if (sense) { DicConsole.ErrorWriteLine("REPORT DENSITY SUPPORT:\n{0}", Sense.PrettifySense(senseBuf)); } else { DensitySupport = seqBuf; DensitySupportHeader = Decoders.SCSI.SSC.DensitySupport.DecodeDensity(seqBuf); } sense = dev.ReportDensitySupport(out seqBuf, out senseBuf, true, false, dev.Timeout, out _); if (sense) { DicConsole.ErrorWriteLine("REPORT DENSITY SUPPORT (MEDIUM):\n{0}", Sense.PrettifySense(senseBuf)); } else { MediumDensitySupport = seqBuf; MediaTypeSupportHeader = Decoders.SCSI.SSC.DensitySupport.DecodeMediumType(seqBuf); } break; } } break; } case DeviceType.MMC: { bool sense = dev.ReadCid(out byte[] mmcBuf, out _, dev.Timeout, out _); if (!sense) { CID = mmcBuf; } sense = dev.ReadCsd(out mmcBuf, out _, dev.Timeout, out _); if (!sense) { CSD = mmcBuf; } sense = dev.ReadOcr(out mmcBuf, out _, dev.Timeout, out _); if (!sense) { OCR = mmcBuf; } sense = dev.ReadExtendedCsd(out mmcBuf, out _, dev.Timeout, out _); if (!sense) { ExtendedCSD = mmcBuf; } } break; case DeviceType.SecureDigital: { bool sense = dev.ReadCid(out byte[] sdBuf, out _, dev.Timeout, out _); if (!sense) { CID = sdBuf; } sense = dev.ReadCsd(out sdBuf, out _, dev.Timeout, out _); if (!sense) { CSD = sdBuf; } sense = dev.ReadSdocr(out sdBuf, out _, dev.Timeout, out _); if (!sense) { OCR = sdBuf; } sense = dev.ReadScr(out sdBuf, out _, dev.Timeout, out _); if (!sense) { SCR = sdBuf; } } break; default: DicConsole.ErrorWriteLine("Unknown device type {0}, cannot get information.", dev.Type); break; } }
/// <summary> /// Opens the device for sending direct commands /// </summary> /// <param name="devicePath">Device path</param> public Device(string devicePath) { PlatformId = DetectOS.GetRealPlatformID(); Timeout = 15; Error = false; IsRemovable = false; switch (PlatformId) { case PlatformID.Win32NT: { FileHandle = Extern.CreateFile(devicePath, FileAccess.GenericRead | FileAccess.GenericWrite, FileShare.Read | FileShare.Write, IntPtr.Zero, FileMode.OpenExisting, FileAttributes.Normal, IntPtr.Zero); if (((SafeFileHandle)FileHandle).IsInvalid) { Error = true; LastError = Marshal.GetLastWin32Error(); } break; } case PlatformID.Linux: { FileHandle = Linux.Extern.open(devicePath, FileFlags.ReadWrite | FileFlags.NonBlocking | FileFlags.CreateNew); if ((int)FileHandle < 0) { LastError = Marshal.GetLastWin32Error(); if (LastError == 13 || LastError == 30) // EACCES or EROFS { FileHandle = Linux.Extern.open(devicePath, FileFlags.Readonly | FileFlags.NonBlocking); if ((int)FileHandle < 0) { Error = true; LastError = Marshal.GetLastWin32Error(); } } else { Error = true; } LastError = Marshal.GetLastWin32Error(); } break; } case PlatformID.FreeBSD: { FileHandle = FreeBSD.Extern.cam_open_device(devicePath, FreeBSD.FileFlags.ReadWrite); if (((IntPtr)FileHandle).ToInt64() == 0) { Error = true; LastError = Marshal.GetLastWin32Error(); } CamDevice camDevice = (CamDevice)Marshal.PtrToStructure((IntPtr)FileHandle, typeof(CamDevice)); if (StringHandlers.CToString(camDevice.SimName) == "ata") { throw new InvalidOperationException("Parallel ATA devices are not supported on FreeBSD due to upstream bug #224250."); } break; } default: throw new InvalidOperationException($"Platform {PlatformId} not yet supported."); } if (Error) { throw new SystemException($"Error {LastError} opening device."); } Type = DeviceType.Unknown; ScsiType = PeripheralDeviceTypes.UnknownDevice; byte[] ataBuf; byte[] inqBuf = null; if (Error) { throw new SystemException($"Error {LastError} trying device."); } bool scsiSense = true; // Windows is answering SCSI INQUIRY for all device types so it needs to be detected first switch (PlatformId) { case PlatformID.Win32NT: StoragePropertyQuery query = new StoragePropertyQuery(); query.PropertyId = StoragePropertyId.Device; query.QueryType = StorageQueryType.Standard; query.AdditionalParameters = new byte[1]; IntPtr descriptorPtr = Marshal.AllocHGlobal(1000); byte[] descriptorB = new byte[1000]; uint returned = 0; int error = 0; bool hasError = !Extern.DeviceIoControlStorageQuery((SafeFileHandle)FileHandle, WindowsIoctl.IoctlStorageQueryProperty, ref query, (uint)Marshal.SizeOf(query), descriptorPtr, 1000, ref returned, IntPtr.Zero); if (hasError) { error = Marshal.GetLastWin32Error(); } Marshal.Copy(descriptorPtr, descriptorB, 0, 1000); if (!hasError && error == 0) { StorageDeviceDescriptor descriptor = new StorageDeviceDescriptor { Version = BitConverter.ToUInt32(descriptorB, 0), Size = BitConverter.ToUInt32(descriptorB, 4), DeviceType = descriptorB[8], DeviceTypeModifier = descriptorB[9], RemovableMedia = descriptorB[10] > 0, CommandQueueing = descriptorB[11] > 0, VendorIdOffset = BitConverter.ToInt32(descriptorB, 12), ProductIdOffset = BitConverter.ToInt32(descriptorB, 16), ProductRevisionOffset = BitConverter.ToInt32(descriptorB, 20), SerialNumberOffset = BitConverter.ToInt32(descriptorB, 24), BusType = (StorageBusType)BitConverter.ToUInt32(descriptorB, 28), RawPropertiesLength = BitConverter.ToUInt32(descriptorB, 32) }; descriptor.RawDeviceProperties = new byte[descriptor.RawPropertiesLength]; Array.Copy(descriptorB, 36, descriptor.RawDeviceProperties, 0, descriptor.RawPropertiesLength); switch (descriptor.BusType) { case StorageBusType.SCSI: case StorageBusType.SSA: case StorageBusType.Fibre: case StorageBusType.iSCSI: case StorageBusType.SAS: Type = DeviceType.SCSI; break; case StorageBusType.FireWire: IsFireWire = true; Type = DeviceType.SCSI; break; case StorageBusType.USB: IsUsb = true; Type = DeviceType.SCSI; break; case StorageBusType.ATAPI: Type = DeviceType.ATAPI; break; case StorageBusType.ATA: case StorageBusType.SATA: Type = DeviceType.ATA; break; case StorageBusType.MultiMediaCard: Type = DeviceType.MMC; break; case StorageBusType.SecureDigital: Type = DeviceType.SecureDigital; break; case StorageBusType.NVMe: Type = DeviceType.NVMe; break; } switch (Type) { case DeviceType.SCSI: case DeviceType.ATAPI: scsiSense = ScsiInquiry(out inqBuf, out _); break; case DeviceType.ATA: bool atapiSense = AtapiIdentify(out ataBuf, out _); if (!atapiSense) { Type = DeviceType.ATAPI; Identify.IdentifyDevice?ataid = Identify.Decode(ataBuf); if (ataid.HasValue) { scsiSense = ScsiInquiry(out inqBuf, out _); } } else { Manufacturer = "ATA"; } break; } } Marshal.FreeHGlobal(descriptorPtr); if (Windows.Command.IsSdhci((SafeFileHandle)FileHandle)) { byte[] sdBuffer = new byte[16]; LastError = Windows.Command.SendMmcCommand((SafeFileHandle)FileHandle, MmcCommands.SendCsd, false, false, MmcFlags.ResponseSpiR2 | MmcFlags.ResponseR2 | MmcFlags.CommandAc, 0, 16, 1, ref sdBuffer, out _, out _, out bool sense); if (!sense) { cachedCsd = new byte[16]; Array.Copy(sdBuffer, 0, cachedCsd, 0, 16); } sdBuffer = new byte[16]; LastError = Windows.Command.SendMmcCommand((SafeFileHandle)FileHandle, MmcCommands.SendCid, false, false, MmcFlags.ResponseSpiR2 | MmcFlags.ResponseR2 | MmcFlags.CommandAc, 0, 16, 1, ref sdBuffer, out _, out _, out sense); if (!sense) { cachedCid = new byte[16]; Array.Copy(sdBuffer, 0, cachedCid, 0, 16); } sdBuffer = new byte[8]; LastError = Windows.Command.SendMmcCommand((SafeFileHandle)FileHandle, (MmcCommands)SecureDigitalCommands.SendScr, false, true, MmcFlags.ResponseSpiR1 | MmcFlags.ResponseR1 | MmcFlags.CommandAdtc, 0, 8, 1, ref sdBuffer, out _, out _, out sense); if (!sense) { cachedScr = new byte[8]; Array.Copy(sdBuffer, 0, cachedScr, 0, 8); } if (cachedScr != null) { sdBuffer = new byte[4]; LastError = Windows.Command.SendMmcCommand((SafeFileHandle)FileHandle, (MmcCommands)SecureDigitalCommands .SendOperatingCondition, false, true, MmcFlags.ResponseSpiR3 | MmcFlags.ResponseR3 | MmcFlags.CommandBcr, 0, 4, 1, ref sdBuffer, out _, out _, out sense); if (!sense) { cachedScr = new byte[4]; Array.Copy(sdBuffer, 0, cachedScr, 0, 4); } } else { sdBuffer = new byte[4]; LastError = Windows.Command.SendMmcCommand((SafeFileHandle)FileHandle, MmcCommands.SendOpCond, false, true, MmcFlags.ResponseSpiR3 | MmcFlags.ResponseR3 | MmcFlags.CommandBcr, 0, 4, 1, ref sdBuffer, out _, out _, out sense); if (!sense) { cachedScr = new byte[4]; Array.Copy(sdBuffer, 0, cachedScr, 0, 4); } } } break; case PlatformID.Linux: if (devicePath.StartsWith("/dev/sd", StringComparison.Ordinal) || devicePath.StartsWith("/dev/sr", StringComparison.Ordinal) || devicePath.StartsWith("/dev/st", StringComparison.Ordinal)) { scsiSense = ScsiInquiry(out inqBuf, out _); } // MultiMediaCard and SecureDigital go here else if (devicePath.StartsWith("/dev/mmcblk", StringComparison.Ordinal)) { string devPath = devicePath.Substring(5); if (File.Exists("/sys/block/" + devPath + "/device/csd")) { int len = ConvertFromHexAscii("/sys/block/" + devPath + "/device/csd", out cachedCsd); if (len == 0) { cachedCsd = null; } } if (File.Exists("/sys/block/" + devPath + "/device/cid")) { int len = ConvertFromHexAscii("/sys/block/" + devPath + "/device/cid", out cachedCid); if (len == 0) { cachedCid = null; } } if (File.Exists("/sys/block/" + devPath + "/device/scr")) { int len = ConvertFromHexAscii("/sys/block/" + devPath + "/device/scr", out cachedScr); if (len == 0) { cachedScr = null; } } if (File.Exists("/sys/block/" + devPath + "/device/ocr")) { int len = ConvertFromHexAscii("/sys/block/" + devPath + "/device/ocr", out cachedOcr); if (len == 0) { cachedOcr = null; } } } break; default: scsiSense = ScsiInquiry(out inqBuf, out _); break; } #region SecureDigital / MultiMediaCard if (cachedCid != null) { ScsiType = PeripheralDeviceTypes.DirectAccess; IsRemovable = false; if (cachedScr != null) { Type = DeviceType.SecureDigital; CID decoded = Decoders.SecureDigital.Decoders.DecodeCID(cachedCid); Manufacturer = VendorString.Prettify(decoded.Manufacturer); Model = decoded.ProductName; Revision = $"{(decoded.ProductRevision & 0xF0) >> 4:X2}.{decoded.ProductRevision & 0x0F:X2}"; Serial = $"{decoded.ProductSerialNumber}"; } else { Type = DeviceType.MMC; Decoders.MMC.CID decoded = Decoders.MMC.Decoders.DecodeCID(cachedCid); Manufacturer = Decoders.MMC.VendorString.Prettify(decoded.Manufacturer); Model = decoded.ProductName; Revision = $"{(decoded.ProductRevision & 0xF0) >> 4:X2}.{decoded.ProductRevision & 0x0F:X2}"; Serial = $"{decoded.ProductSerialNumber}"; } } #endregion SecureDigital / MultiMediaCard #region USB switch (PlatformId) { case PlatformID.Linux: if (devicePath.StartsWith("/dev/sd", StringComparison.Ordinal) || devicePath.StartsWith("/dev/sr", StringComparison.Ordinal) || devicePath.StartsWith("/dev/st", StringComparison.Ordinal)) { string devPath = devicePath.Substring(5); if (Directory.Exists("/sys/block/" + devPath)) { string resolvedLink = Linux.Command.ReadLink("/sys/block/" + devPath); resolvedLink = "/sys" + resolvedLink.Substring(2); if (!string.IsNullOrEmpty(resolvedLink)) { while (resolvedLink.Contains("usb")) { resolvedLink = Path.GetDirectoryName(resolvedLink); if (!File.Exists(resolvedLink + "/descriptors") || !File.Exists(resolvedLink + "/idProduct") || !File.Exists(resolvedLink + "/idVendor")) { continue; } FileStream usbFs = new FileStream(resolvedLink + "/descriptors", System.IO.FileMode.Open, System.IO.FileAccess.Read); byte[] usbBuf = new byte[65536]; int usbCount = usbFs.Read(usbBuf, 0, 65536); UsbDescriptors = new byte[usbCount]; Array.Copy(usbBuf, 0, UsbDescriptors, 0, usbCount); usbFs.Close(); StreamReader usbSr = new StreamReader(resolvedLink + "/idProduct"); string usbTemp = usbSr.ReadToEnd(); ushort.TryParse(usbTemp, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out usbProduct); usbSr.Close(); usbSr = new StreamReader(resolvedLink + "/idVendor"); usbTemp = usbSr.ReadToEnd(); ushort.TryParse(usbTemp, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out usbVendor); usbSr.Close(); if (File.Exists(resolvedLink + "/manufacturer")) { usbSr = new StreamReader(resolvedLink + "/manufacturer"); UsbManufacturerString = usbSr.ReadToEnd().Trim(); usbSr.Close(); } if (File.Exists(resolvedLink + "/product")) { usbSr = new StreamReader(resolvedLink + "/product"); UsbProductString = usbSr.ReadToEnd().Trim(); usbSr.Close(); } if (File.Exists(resolvedLink + "/serial")) { usbSr = new StreamReader(resolvedLink + "/serial"); UsbSerialString = usbSr.ReadToEnd().Trim(); usbSr.Close(); } IsUsb = true; break; } } } } break; case PlatformID.Win32NT: Usb.UsbDevice usbDevice = null; // I have to search for USB disks, floppies and CD-ROMs as separate device types foreach (string devGuid in new[] { Usb.GuidDevinterfaceFloppy, Usb.GuidDevinterfaceCdrom, Usb.GuidDevinterfaceDisk }) { usbDevice = Usb.FindDrivePath(devicePath, devGuid); if (usbDevice != null) { break; } } if (usbDevice != null) { UsbDescriptors = usbDevice.BinaryDescriptors; usbVendor = (ushort)usbDevice.DeviceDescriptor.idVendor; usbProduct = (ushort)usbDevice.DeviceDescriptor.idProduct; UsbManufacturerString = usbDevice.Manufacturer; UsbProductString = usbDevice.Product; UsbSerialString = usbDevice.SerialNumber; // This is incorrect filled by Windows with SCSI/ATA serial number } break; default: IsUsb = false; break; } #endregion USB #region FireWire if (PlatformId == PlatformID.Linux) { if (devicePath.StartsWith("/dev/sd", StringComparison.Ordinal) || devicePath.StartsWith("/dev/sr", StringComparison.Ordinal) || devicePath.StartsWith("/dev/st", StringComparison.Ordinal)) { string devPath = devicePath.Substring(5); if (Directory.Exists("/sys/block/" + devPath)) { string resolvedLink = Linux.Command.ReadLink("/sys/block/" + devPath); resolvedLink = "/sys" + resolvedLink.Substring(2); if (!string.IsNullOrEmpty(resolvedLink)) { while (resolvedLink.Contains("firewire")) { resolvedLink = Path.GetDirectoryName(resolvedLink); if (!File.Exists(resolvedLink + "/model") || !File.Exists(resolvedLink + "/vendor") || !File.Exists(resolvedLink + "/guid")) { continue; } StreamReader fwSr = new StreamReader(resolvedLink + "/model"); string fwTemp = fwSr.ReadToEnd(); uint.TryParse(fwTemp, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out firewireModel); fwSr.Close(); fwSr = new StreamReader(resolvedLink + "/vendor"); fwTemp = fwSr.ReadToEnd(); uint.TryParse(fwTemp, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out firewireVendor); fwSr.Close(); fwSr = new StreamReader(resolvedLink + "/guid"); fwTemp = fwSr.ReadToEnd(); ulong.TryParse(fwTemp, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out firewireGuid); fwSr.Close(); if (File.Exists(resolvedLink + "/model_name")) { fwSr = new StreamReader(resolvedLink + "/model_name"); FireWireModelName = fwSr.ReadToEnd().Trim(); fwSr.Close(); } if (File.Exists(resolvedLink + "/vendor_name")) { fwSr = new StreamReader(resolvedLink + "/vendor_name"); FireWireVendorName = fwSr.ReadToEnd().Trim(); fwSr.Close(); } IsFireWire = true; break; } } } } } // TODO: Implement for other operating systems else { IsFireWire = false; } #endregion FireWire #region PCMCIA if (PlatformId == PlatformID.Linux) { if (devicePath.StartsWith("/dev/sd", StringComparison.Ordinal) || devicePath.StartsWith("/dev/sr", StringComparison.Ordinal) || devicePath.StartsWith("/dev/st", StringComparison.Ordinal)) { string devPath = devicePath.Substring(5); if (Directory.Exists("/sys/block/" + devPath)) { string resolvedLink = Linux.Command.ReadLink("/sys/block/" + devPath); resolvedLink = "/sys" + resolvedLink.Substring(2); if (!string.IsNullOrEmpty(resolvedLink)) { while (resolvedLink.Contains("/sys/devices")) { resolvedLink = Path.GetDirectoryName(resolvedLink); if (!Directory.Exists(resolvedLink + "/pcmcia_socket")) { continue; } string[] subdirs = Directory.GetDirectories(resolvedLink + "/pcmcia_socket", "pcmcia_socket*", SearchOption.TopDirectoryOnly); if (subdirs.Length <= 0) { continue; } string possibleDir = Path.Combine(resolvedLink, "pcmcia_socket", subdirs[0]); if (!File.Exists(possibleDir + "/card_type") || !File.Exists(possibleDir + "/cis")) { continue; } FileStream cisFs = new FileStream(possibleDir + "/cis", System.IO.FileMode.Open, System.IO.FileAccess.Read); byte[] cisBuf = new byte[65536]; int cisCount = cisFs.Read(cisBuf, 0, 65536); Cis = new byte[cisCount]; Array.Copy(cisBuf, 0, Cis, 0, cisCount); cisFs.Close(); IsPcmcia = true; break; } } } } } // TODO: Implement for other operating systems else { IsPcmcia = false; } #endregion PCMCIA if (!scsiSense) { Inquiry.SCSIInquiry?inquiry = Inquiry.Decode(inqBuf); Type = DeviceType.SCSI; bool serialSense = ScsiInquiry(out inqBuf, out _, 0x80); if (!serialSense) { Serial = EVPD.DecodePage80(inqBuf); } if (inquiry.HasValue) { string tmp = StringHandlers.CToString(inquiry.Value.ProductRevisionLevel); if (tmp != null) { Revision = tmp.Trim(); } tmp = StringHandlers.CToString(inquiry.Value.ProductIdentification); if (tmp != null) { Model = tmp.Trim(); } tmp = StringHandlers.CToString(inquiry.Value.VendorIdentification); if (tmp != null) { Manufacturer = tmp.Trim(); } IsRemovable = inquiry.Value.RMB; ScsiType = (PeripheralDeviceTypes)inquiry.Value.PeripheralDeviceType; } bool atapiSense = AtapiIdentify(out ataBuf, out _); if (!atapiSense) { Type = DeviceType.ATAPI; Identify.IdentifyDevice?ataId = Identify.Decode(ataBuf); if (ataId.HasValue) { Serial = ataId.Value.SerialNumber; } } LastError = 0; Error = false; } if (scsiSense && (IsUsb || IsFireWire) || Manufacturer == "ATA") { bool ataSense = AtaIdentify(out ataBuf, out _); if (!ataSense) { Type = DeviceType.ATA; Identify.IdentifyDevice?ataid = Identify.Decode(ataBuf); if (ataid.HasValue) { string[] separated = ataid.Value.Model.Split(' '); if (separated.Length == 1) { Model = separated[0]; } else { Manufacturer = separated[0]; Model = separated[separated.Length - 1]; } Revision = ataid.Value.FirmwareRevision; Serial = ataid.Value.SerialNumber; ScsiType = PeripheralDeviceTypes.DirectAccess; if ((ushort)ataid.Value.GeneralConfiguration != 0x848A) { IsRemovable |= (ataid.Value.GeneralConfiguration & Identify.GeneralConfigurationBit.Removable) == Identify.GeneralConfigurationBit.Removable; } else { IsCompactFlash = true; } } } } if (Type == DeviceType.Unknown) { Manufacturer = null; Model = null; Revision = null; Serial = null; } if (IsUsb) { if (string.IsNullOrEmpty(Manufacturer)) { Manufacturer = UsbManufacturerString; } if (string.IsNullOrEmpty(Model)) { Model = UsbProductString; } if (string.IsNullOrEmpty(Serial)) { Serial = UsbSerialString; } else { foreach (char c in Serial.Where(char.IsControl)) { Serial = UsbSerialString; } } } if (IsFireWire) { if (string.IsNullOrEmpty(Manufacturer)) { Manufacturer = FireWireVendorName; } if (string.IsNullOrEmpty(Model)) { Model = FireWireModelName; } if (string.IsNullOrEmpty(Serial)) { Serial = $"{firewireGuid:X16}"; } else { foreach (char c in Serial.Where(char.IsControl)) { Serial = $"{firewireGuid:X16}"; } } } // Some optical drives are not getting the correct serial, and IDENTIFY PACKET DEVICE is blocked without // administrator privileges if (ScsiType != PeripheralDeviceTypes.MultiMediaDevice) { return; } bool featureSense = GetConfiguration(out byte[] featureBuffer, out _, 0x0108, MmcGetConfigurationRt.Single, Timeout, out _); if (featureSense) { return; } Features.SeparatedFeatures features = Features.Separate(featureBuffer); if (features.Descriptors?.Length != 1 || features.Descriptors[0].Code != 0x0108) { return; } Feature_0108?serialFeature = Features.Decode_0108(features.Descriptors[0].Data); if (serialFeature is null) { return; } Serial = serialFeature.Value.Serial; }
/// <summary> /// Takes the SCSI EVPD part of a device report and prints it as a list key=value pairs to be sequenced by ASP.NET /// in the rendering /// </summary> /// <param name="pages">EVPD pages</param> /// <param name="vendor">SCSI vendor string</param> /// <param name="evpdPages">List to put the key=value pairs on</param> public static void Report(IEnumerable <ScsiPage> pages, string vendor, ref Dictionary <string, string> evpdPages) { foreach (ScsiPage evpd in pages) { string decoded; if (evpd.page >= 0x01 && evpd.page <= 0x7F) { decoded = EVPD.DecodeASCIIPage(evpd.value); } else if (evpd.page == 0x81) { decoded = EVPD.PrettifyPage_81(evpd.value); } else if (evpd.page == 0x82) { decoded = EVPD.DecodePage82(evpd.value); } else if (evpd.page == 0x83) { decoded = EVPD.PrettifyPage_83(evpd.value); } else if (evpd.page == 0x84) { decoded = EVPD.PrettifyPage_84(evpd.value); } else if (evpd.page == 0x85) { decoded = EVPD.PrettifyPage_85(evpd.value); } else if (evpd.page == 0x86) { decoded = EVPD.PrettifyPage_86(evpd.value); } else if (evpd.page == 0x89) { decoded = EVPD.PrettifyPage_89(evpd.value); } else if (evpd.page == 0xB0) { decoded = EVPD.PrettifyPage_B0(evpd.value); } else if (evpd.page == 0xB2) { decoded = $"TapeAlert Supported Flags Bitmap: 0x{EVPD.DecodePageB2(evpd.value):X16}<br/>"; } else if (evpd.page == 0xB4) { decoded = EVPD.DecodePageB4(evpd.value); } else if (evpd.page == 0xC0 && vendor.Trim() == "quantum") { decoded = EVPD.PrettifyPage_C0_Quantum(evpd.value); } else if (evpd.page == 0xC0 && vendor.Trim() == "seagate") { decoded = EVPD.PrettifyPage_C0_Seagate(evpd.value); } else if (evpd.page == 0xC0 && vendor.Trim() == "ibm") { decoded = EVPD.PrettifyPage_C0_IBM(evpd.value); } else if (evpd.page == 0xC1 && vendor.Trim() == "ibm") { decoded = EVPD.PrettifyPage_C1_IBM(evpd.value); } else if ((evpd.page == 0xC0 || evpd.page == 0xC1) && vendor.Trim() == "certance") { decoded = EVPD.PrettifyPage_C0_C1_Certance(evpd.value); } else if ((evpd.page == 0xC2 || evpd.page == 0xC3 || evpd.page == 0xC4 || evpd.page == 0xC5 || evpd.page == 0xC6) && vendor.Trim() == "certance") { decoded = EVPD.PrettifyPage_C2_C3_C4_C5_C6_Certance(evpd.value); } else if ((evpd.page == 0xC0 || evpd.page == 0xC1 || evpd.page == 0xC2 || evpd.page == 0xC3 || evpd.page == 0xC4 || evpd.page == 0xC5) && vendor.Trim() == "hp") { decoded = EVPD.PrettifyPage_C0_to_C5_HP(evpd.value); } else if (evpd.page == 0xDF && vendor.Trim() == "certance") { decoded = EVPD.PrettifyPage_DF_Certance(evpd.value); } else { decoded = "Undecoded"; } if (!string.IsNullOrEmpty(decoded)) { decoded = decoded.Replace("\n", "<br/>"); } evpdPages.Add($"EVPD page {evpd.page:X2}h", decoded); } }
public ScsiInfoViewModel(byte[] scsiInquiryData, Inquiry?scsiInquiry, Dictionary <byte, byte[]> scsiEvpdPages, Modes.DecodedMode?scsiMode, PeripheralDeviceTypes scsiType, byte[] scsiModeSense6, byte[] scsiModeSense10, byte[] mmcConfiguration, Window view) { InquiryData = scsiInquiryData; _scsiModeSense6 = scsiModeSense6; _scsiModeSense10 = scsiModeSense10; _configuration = mmcConfiguration; _view = view; ModeSensePages = new ObservableCollection <ScsiPageModel>(); EvpdPages = new ObservableCollection <ScsiPageModel>(); MmcFeatures = new ObservableCollection <ScsiPageModel>(); SaveInquiryBinaryCommand = ReactiveCommand.Create(ExecuteSaveInquiryBinaryCommand); SaveInquiryTextCommand = ReactiveCommand.Create(ExecuteSaveInquiryTextCommand); SaveModeSense6Command = ReactiveCommand.Create(ExecuteSaveModeSense6Command); SaveModeSense10Command = ReactiveCommand.Create(ExecuteSaveModeSense10Command); SaveEvpdPageCommand = ReactiveCommand.Create(ExecuteSaveEvpdPageCommand); SaveMmcFeaturesCommand = ReactiveCommand.Create(ExecuteSaveMmcFeaturesCommand); if (InquiryData == null || !scsiInquiry.HasValue) { return; } ScsiInquiryText = Decoders.SCSI.Inquiry.Prettify(scsiInquiry); if (scsiMode.HasValue) { ModeSensePages.Add(new ScsiPageModel { Page = "Header", Description = Modes.PrettifyModeHeader(scsiMode.Value.Header, scsiType) }); if (scsiMode.Value.Pages != null) { foreach (Modes.ModePage page in scsiMode.Value.Pages.OrderBy(t => t.Page).ThenBy(t => t.Subpage)) { string pageNumberText = page.Subpage == 0 ? $"MODE {page.Page:X2}h" : $"MODE {page.Page:X2} Subpage {page.Subpage:X2}"; string decodedText; switch (page.Page) { case 0x00: { if (scsiType == PeripheralDeviceTypes.MultiMediaDevice && page.Subpage == 0) { decodedText = Modes.PrettifyModePage_00_SFF(page.PageResponse); } else { decodedText = "Undecoded"; } break; } case 0x01: { if (page.Subpage == 0) { decodedText = scsiType == PeripheralDeviceTypes.MultiMediaDevice ? Modes.PrettifyModePage_01_MMC(page.PageResponse) : Modes.PrettifyModePage_01(page.PageResponse); } else { goto default; } break; } case 0x02: { if (page.Subpage == 0) { decodedText = Modes.PrettifyModePage_02(page.PageResponse); } else { goto default; } break; } case 0x03: { if (page.Subpage == 0) { decodedText = Modes.PrettifyModePage_03(page.PageResponse); } else { goto default; } break; } case 0x04: { if (page.Subpage == 0) { decodedText = Modes.PrettifyModePage_04(page.PageResponse); } else { goto default; } break; } case 0x05: { if (page.Subpage == 0) { decodedText = Modes.PrettifyModePage_05(page.PageResponse); } else { goto default; } break; } case 0x06: { if (page.Subpage == 0) { decodedText = Modes.PrettifyModePage_06(page.PageResponse); } else { goto default; } break; } case 0x07: { if (page.Subpage == 0) { decodedText = scsiType == PeripheralDeviceTypes.MultiMediaDevice ? Modes.PrettifyModePage_07_MMC(page.PageResponse) : Modes.PrettifyModePage_07(page.PageResponse); } else { goto default; } break; } case 0x08: { if (page.Subpage == 0) { decodedText = Modes.PrettifyModePage_08(page.PageResponse); } else { goto default; } break; } case 0x0A: { if (page.Subpage == 0) { decodedText = Modes.PrettifyModePage_0A(page.PageResponse); } else if (page.Subpage == 1) { decodedText = Modes.PrettifyModePage_0A_S01(page.PageResponse); } else { goto default; } break; } case 0x0B: { if (page.Subpage == 0) { decodedText = Modes.PrettifyModePage_0B(page.PageResponse); } else { goto default; } break; } case 0x0D: { if (page.Subpage == 0) { decodedText = Modes.PrettifyModePage_0D(page.PageResponse); } else { goto default; } break; } case 0x0E: { if (page.Subpage == 0) { decodedText = Modes.PrettifyModePage_0E(page.PageResponse); } else { goto default; } break; } case 0x0F: { if (page.Subpage == 0) { decodedText = Modes.PrettifyModePage_0F(page.PageResponse); } else { goto default; } break; } case 0x10: { if (page.Subpage == 0) { decodedText = scsiType == PeripheralDeviceTypes.SequentialAccess ? Modes.PrettifyModePage_10_SSC(page.PageResponse) : Modes.PrettifyModePage_10(page.PageResponse); } else { goto default; } break; } case 0x11: { if (page.Subpage == 0) { decodedText = Modes.PrettifyModePage_11(page.PageResponse); } else { goto default; } break; } case 0x12: case 0x13: case 0x14: { if (page.Subpage == 0) { decodedText = Modes.PrettifyModePage_12_13_14(page.PageResponse); } else { goto default; } break; } case 0x1A: { if (page.Subpage == 0) { decodedText = Modes.PrettifyModePage_1A(page.PageResponse); } else if (page.Subpage == 1) { decodedText = Modes.PrettifyModePage_1A_S01(page.PageResponse); } else { goto default; } break; } case 0x1B: { if (page.Subpage == 0) { decodedText = Modes.PrettifyModePage_1B(page.PageResponse); } else { goto default; } break; } case 0x1C: { if (page.Subpage == 0) { decodedText = scsiType == PeripheralDeviceTypes.MultiMediaDevice ? Modes.PrettifyModePage_1C_SFF(page.PageResponse) : Modes.PrettifyModePage_1C(page.PageResponse); } else if (page.Subpage == 1) { decodedText = Modes.PrettifyModePage_1C_S01(page.PageResponse); } else { goto default; } break; } case 0x1D: { if (page.Subpage == 0) { decodedText = Modes.PrettifyModePage_1D(page.PageResponse); } else { goto default; } break; } case 0x21: { if (StringHandlers.CToString(scsiInquiry.Value.VendorIdentification).Trim() == "CERTANCE") { decodedText = Modes.PrettifyCertanceModePage_21(page.PageResponse); } else { goto default; } break; } case 0x22: { if (StringHandlers.CToString(scsiInquiry.Value.VendorIdentification).Trim() == "CERTANCE") { decodedText = Modes.PrettifyCertanceModePage_22(page.PageResponse); } else { goto default; } break; } case 0x24: { if (StringHandlers.CToString(scsiInquiry.Value.VendorIdentification).Trim() == "IBM") { decodedText = Modes.PrettifyIBMModePage_24(page.PageResponse); } else { goto default; } break; } case 0x2A: { if (page.Subpage == 0) { decodedText = Modes.PrettifyModePage_2A(page.PageResponse); } else { goto default; } break; } case 0x2F: { if (StringHandlers.CToString(scsiInquiry.Value.VendorIdentification).Trim() == "IBM") { decodedText = Modes.PrettifyIBMModePage_2F(page.PageResponse); } else { goto default; } break; } case 0x30: { if (Modes.IsAppleModePage_30(page.PageResponse)) { decodedText = "Drive identifies as Apple OEM drive"; } else { goto default; } break; } case 0x3B: { if (StringHandlers.CToString(scsiInquiry.Value.VendorIdentification).Trim() == "HP") { decodedText = Modes.PrettifyHPModePage_3B(page.PageResponse); } else { goto default; } break; } case 0x3C: { if (StringHandlers.CToString(scsiInquiry.Value.VendorIdentification).Trim() == "HP") { decodedText = Modes.PrettifyHPModePage_3C(page.PageResponse); } else { goto default; } break; } case 0x3D: { if (StringHandlers.CToString(scsiInquiry.Value.VendorIdentification).Trim() == "IBM") { decodedText = Modes.PrettifyIBMModePage_3D(page.PageResponse); } else if (StringHandlers.CToString(scsiInquiry.Value.VendorIdentification).Trim() == "HP") { decodedText = Modes.PrettifyHPModePage_3D(page.PageResponse); } else { goto default; } break; } case 0x3E: { if (StringHandlers.CToString(scsiInquiry.Value.VendorIdentification).Trim() == "FUJITSU") { decodedText = Modes.PrettifyFujitsuModePage_3E(page.PageResponse); } else if (StringHandlers.CToString(scsiInquiry.Value.VendorIdentification).Trim() == "HP") { decodedText = Modes.PrettifyHPModePage_3E(page.PageResponse); } else { goto default; } break; } default: { decodedText = "Undecoded"; break; } } // TODO: Automatic error reporting if (decodedText == null) { decodedText = "Error decoding page, please open an issue."; } ModeSensePages.Add(new ScsiPageModel { Page = pageNumberText, Description = decodedText }); } } } if (scsiEvpdPages != null) { foreach (KeyValuePair <byte, byte[]> page in scsiEvpdPages.OrderBy(t => t.Key)) { string evpdPageTitle = ""; string evpdDecodedPage; if (page.Key >= 0x01 && page.Key <= 0x7F) { evpdPageTitle = $"ASCII Page {page.Key:X2}h"; evpdDecodedPage = EVPD.DecodeASCIIPage(page.Value); } else if (page.Key == 0x80) { evpdPageTitle = "Unit Serial Number"; evpdDecodedPage = EVPD.DecodePage80(page.Value); } else if (page.Key == 0x81) { evpdPageTitle = "SCSI Implemented operating definitions"; evpdDecodedPage = EVPD.PrettifyPage_81(page.Value); } else if (page.Key == 0x82) { evpdPageTitle = "ASCII implemented operating definitions"; evpdDecodedPage = EVPD.DecodePage82(page.Value); } else if (page.Key == 0x83) { evpdPageTitle = "SCSI Device identification"; evpdDecodedPage = EVPD.PrettifyPage_83(page.Value); } else if (page.Key == 0x84) { evpdPageTitle = "SCSI Software Interface Identifiers"; evpdDecodedPage = EVPD.PrettifyPage_84(page.Value); } else if (page.Key == 0x85) { evpdPageTitle = "SCSI Management Network Addresses"; evpdDecodedPage = EVPD.PrettifyPage_85(page.Value); } else if (page.Key == 0x86) { evpdPageTitle = "SCSI Extended INQUIRY Data"; evpdDecodedPage = EVPD.PrettifyPage_86(page.Value); } else if (page.Key == 0x89) { evpdPageTitle = "SCSI to ATA Translation Layer Data"; evpdDecodedPage = EVPD.PrettifyPage_89(page.Value); } else if (page.Key == 0xB0) { evpdPageTitle = "SCSI Sequential-access Device Capabilities"; evpdDecodedPage = EVPD.PrettifyPage_B0(page.Value); } else if (page.Key == 0xB1) { evpdPageTitle = "Manufacturer-assigned Serial Number"; evpdDecodedPage = EVPD.DecodePageB1(page.Value); } else if (page.Key == 0xB2) { evpdPageTitle = "TapeAlert Supported Flags Bitmap"; evpdDecodedPage = $"0x{EVPD.DecodePageB2(page.Value):X16}"; } else if (page.Key == 0xB3) { evpdPageTitle = "Automation Device Serial Number"; evpdDecodedPage = EVPD.DecodePageB3(page.Value); } else if (page.Key == 0xB4) { evpdPageTitle = "Data Transfer Device Element Address"; evpdDecodedPage = EVPD.DecodePageB4(page.Value); } else if (page.Key == 0xC0 && StringHandlers.CToString(scsiInquiry.Value.VendorIdentification).ToLowerInvariant(). Trim() == "quantum") { evpdPageTitle = "Quantum Firmware Build Information page"; evpdDecodedPage = EVPD.PrettifyPage_C0_Quantum(page.Value); } else if (page.Key == 0xC0 && StringHandlers.CToString(scsiInquiry.Value.VendorIdentification).ToLowerInvariant(). Trim() == "seagate") { evpdPageTitle = "Seagate Firmware Numbers page"; evpdDecodedPage = EVPD.PrettifyPage_C0_Seagate(page.Value); } else if (page.Key == 0xC0 && StringHandlers.CToString(scsiInquiry.Value.VendorIdentification).ToLowerInvariant(). Trim() == "ibm") { evpdPageTitle = "IBM Drive Component Revision Levels page"; evpdDecodedPage = EVPD.PrettifyPage_C0_IBM(page.Value); } else if (page.Key == 0xC1 && StringHandlers.CToString(scsiInquiry.Value.VendorIdentification).ToLowerInvariant(). Trim() == "ibm") { evpdPageTitle = "IBM Drive Serial Numbers page"; evpdDecodedPage = EVPD.PrettifyPage_C1_IBM(page.Value); } else if ((page.Key == 0xC0 || page.Key == 0xC1) && StringHandlers.CToString(scsiInquiry.Value.VendorIdentification).ToLowerInvariant(). Trim() == "certance") { evpdPageTitle = "Certance Drive Component Revision Levels page"; evpdDecodedPage = EVPD.PrettifyPage_C0_C1_Certance(page.Value); } else if ((page.Key == 0xC2 || page.Key == 0xC3 || page.Key == 0xC4 || page.Key == 0xC5 || page.Key == 0xC6) && StringHandlers.CToString(scsiInquiry.Value.VendorIdentification).ToLowerInvariant(). Trim() == "certance") { switch (page.Key) { case 0xC2: evpdPageTitle = "Head Assembly Serial Number"; break; case 0xC3: evpdPageTitle = "Reel Motor 1 Serial Number"; break; case 0xC4: evpdPageTitle = "Reel Motor 2 Serial Number"; break; case 0xC5: evpdPageTitle = "Board Serial Number"; break; case 0xC6: evpdPageTitle = "Base Mechanical Serial Number"; break; } evpdDecodedPage = EVPD.PrettifyPage_C2_C3_C4_C5_C6_Certance(page.Value); } else if ((page.Key == 0xC0 || page.Key == 0xC1 || page.Key == 0xC2 || page.Key == 0xC3 || page.Key == 0xC4 || page.Key == 0xC5) && StringHandlers.CToString(scsiInquiry.Value.VendorIdentification).ToLowerInvariant(). Trim() == "hp") { switch (page.Key) { case 0xC0: evpdPageTitle = "HP Drive Firmware Revision Levels page:"; break; case 0xC1: evpdPageTitle = "HP Drive Hardware Revision Levels page:"; break; case 0xC2: evpdPageTitle = "HP Drive PCA Revision Levels page:"; break; case 0xC3: evpdPageTitle = "HP Drive Mechanism Revision Levels page:"; break; case 0xC4: evpdPageTitle = "HP Drive Head Assembly Revision Levels page:"; break; case 0xC5: evpdPageTitle = "HP Drive ACI Revision Levels page:"; break; } evpdDecodedPage = EVPD.PrettifyPage_C0_to_C5_HP(page.Value); } else if (page.Key == 0xDF && StringHandlers.CToString(scsiInquiry.Value.VendorIdentification).ToLowerInvariant(). Trim() == "certance") { evpdPageTitle = "Certance drive status page"; evpdDecodedPage = EVPD.PrettifyPage_DF_Certance(page.Value); } else { if (page.Key == 0x00) { continue; } evpdPageTitle = $"Page {page.Key:X2}h"; evpdDecodedPage = "Undecoded"; AaruConsole.DebugWriteLine("Device-Info command", "Found undecoded SCSI VPD page 0x{0:X2}", page.Key); } EvpdPages.Add(new ScsiPageModel { Page = evpdPageTitle, Data = page.Value, Description = evpdDecodedPage }); } } if (_configuration != null) { Features.SeparatedFeatures ftr = Features.Separate(_configuration); AaruConsole.DebugWriteLine("Device-Info command", "GET CONFIGURATION length is {0} bytes", ftr.DataLength); AaruConsole.DebugWriteLine("Device-Info command", "GET CONFIGURATION current profile is {0:X4}h", ftr.CurrentProfile); if (ftr.Descriptors != null) { foreach (Features.FeatureDescriptor desc in ftr.Descriptors) { string featureNumber = $"Feature {desc.Code:X4}h"; string featureDescription; AaruConsole.DebugWriteLine("Device-Info command", "Feature {0:X4}h", desc.Code); switch (desc.Code) { case 0x0000: featureDescription = Features.Prettify_0000(desc.Data); break; case 0x0001: featureDescription = Features.Prettify_0001(desc.Data); break; case 0x0002: featureDescription = Features.Prettify_0002(desc.Data); break; case 0x0003: featureDescription = Features.Prettify_0003(desc.Data); break; case 0x0004: featureDescription = Features.Prettify_0004(desc.Data); break; case 0x0010: featureDescription = Features.Prettify_0010(desc.Data); break; case 0x001D: featureDescription = Features.Prettify_001D(desc.Data); break; case 0x001E: featureDescription = Features.Prettify_001E(desc.Data); break; case 0x001F: featureDescription = Features.Prettify_001F(desc.Data); break; case 0x0020: featureDescription = Features.Prettify_0020(desc.Data); break; case 0x0021: featureDescription = Features.Prettify_0021(desc.Data); break; case 0x0022: featureDescription = Features.Prettify_0022(desc.Data); break; case 0x0023: featureDescription = Features.Prettify_0023(desc.Data); break; case 0x0024: featureDescription = Features.Prettify_0024(desc.Data); break; case 0x0025: featureDescription = Features.Prettify_0025(desc.Data); break; case 0x0026: featureDescription = Features.Prettify_0026(desc.Data); break; case 0x0027: featureDescription = Features.Prettify_0027(desc.Data); break; case 0x0028: featureDescription = Features.Prettify_0028(desc.Data); break; case 0x0029: featureDescription = Features.Prettify_0029(desc.Data); break; case 0x002A: featureDescription = Features.Prettify_002A(desc.Data); break; case 0x002B: featureDescription = Features.Prettify_002B(desc.Data); break; case 0x002C: featureDescription = Features.Prettify_002C(desc.Data); break; case 0x002D: featureDescription = Features.Prettify_002D(desc.Data); break; case 0x002E: featureDescription = Features.Prettify_002E(desc.Data); break; case 0x002F: featureDescription = Features.Prettify_002F(desc.Data); break; case 0x0030: featureDescription = Features.Prettify_0030(desc.Data); break; case 0x0031: featureDescription = Features.Prettify_0031(desc.Data); break; case 0x0032: featureDescription = Features.Prettify_0032(desc.Data); break; case 0x0033: featureDescription = Features.Prettify_0033(desc.Data); break; case 0x0035: featureDescription = Features.Prettify_0035(desc.Data); break; case 0x0037: featureDescription = Features.Prettify_0037(desc.Data); break; case 0x0038: featureDescription = Features.Prettify_0038(desc.Data); break; case 0x003A: featureDescription = Features.Prettify_003A(desc.Data); break; case 0x003B: featureDescription = Features.Prettify_003B(desc.Data); break; case 0x0040: featureDescription = Features.Prettify_0040(desc.Data); break; case 0x0041: featureDescription = Features.Prettify_0041(desc.Data); break; case 0x0042: featureDescription = Features.Prettify_0042(desc.Data); break; case 0x0050: featureDescription = Features.Prettify_0050(desc.Data); break; case 0x0051: featureDescription = Features.Prettify_0051(desc.Data); break; case 0x0080: featureDescription = Features.Prettify_0080(desc.Data); break; case 0x0100: featureDescription = Features.Prettify_0100(desc.Data); break; case 0x0101: featureDescription = Features.Prettify_0101(desc.Data); break; case 0x0102: featureDescription = Features.Prettify_0102(desc.Data); break; case 0x0103: featureDescription = Features.Prettify_0103(desc.Data); break; case 0x0104: featureDescription = Features.Prettify_0104(desc.Data); break; case 0x0105: featureDescription = Features.Prettify_0105(desc.Data); break; case 0x0106: featureDescription = Features.Prettify_0106(desc.Data); break; case 0x0107: featureDescription = Features.Prettify_0107(desc.Data); break; case 0x0108: featureDescription = Features.Prettify_0108(desc.Data); break; case 0x0109: featureDescription = Features.Prettify_0109(desc.Data); break; case 0x010A: featureDescription = Features.Prettify_010A(desc.Data); break; case 0x010B: featureDescription = Features.Prettify_010B(desc.Data); break; case 0x010C: featureDescription = Features.Prettify_010C(desc.Data); break; case 0x010D: featureDescription = Features.Prettify_010D(desc.Data); break; case 0x010E: featureDescription = Features.Prettify_010E(desc.Data); break; case 0x0110: featureDescription = Features.Prettify_0110(desc.Data); break; case 0x0113: featureDescription = Features.Prettify_0113(desc.Data); break; case 0x0142: featureDescription = Features.Prettify_0142(desc.Data); break; default: featureDescription = "Unknown feature"; break; } MmcFeatures.Add(new ScsiPageModel { Page = featureNumber, Description = featureDescription }); } } else { AaruConsole.DebugWriteLine("Device-Info command", "GET CONFIGURATION returned no feature descriptors"); } } }
public List <ScsiPage> ReportEvpdPages(string vendor) { AaruConsole.WriteLine("Querying list of SCSI EVPDs..."); bool sense = _dev.ScsiInquiry(out byte[] buffer, out _, 0x00); if (sense) { return(null); } byte[] evpdPages = EVPD.DecodePage00(buffer); if (evpdPages == null || evpdPages.Length <= 0) { return(null); } List <ScsiPage> evpds = new List <ScsiPage>(); foreach (byte page in evpdPages.Where(page => page != 0x80)) { AaruConsole.WriteLine("Querying SCSI EVPD {0:X2}h...", page); sense = _dev.ScsiInquiry(out buffer, out _, page); if (sense) { continue; } byte[] empty; switch (page) { case 0x83: buffer = ClearPage83(buffer); break; case 0x80: byte[] identify = new byte[512]; Array.Copy(buffer, 60, identify, 0, 512); identify = ClearIdentify(identify); Array.Copy(identify, 0, buffer, 60, 512); break; case 0xB1: case 0xB3: empty = new byte[buffer.Length - 4]; Array.Copy(empty, 0, buffer, 4, buffer.Length - 4); break; case 0xC1 when vendor == "ibm": empty = new byte[12]; Array.Copy(empty, 0, buffer, 4, 12); Array.Copy(empty, 0, buffer, 16, 12); break; case 0xC2 when vendor == "certance": case 0xC3 when vendor == "certance": case 0xC4 when vendor == "certance": case 0xC5 when vendor == "certance": case 0xC6 when vendor == "certance": Array.Copy(new byte[12], 0, buffer, 4, 12); break; } var evpd = new ScsiPage { page = page, value = buffer }; evpds.Add(evpd); } return(evpds.Count > 0 ? evpds : null); }
internal void LoadData(byte[] scsiInquiryData, CommonTypes.Structs.Devices.SCSI.Inquiry?scsiInquiry, Dictionary <byte, byte[]> scsiEvpdPages, Modes.DecodedMode?scsiMode, PeripheralDeviceTypes scsiType, byte[] scsiModeSense6, byte[] scsiModeSense10, byte[] mmcConfiguration) { inquiryData = scsiInquiryData; inquiry = scsiInquiry; evpdPages = scsiEvpdPages; mode = scsiMode; type = scsiType; modeSense6 = scsiModeSense6; modeSense10 = scsiModeSense10; configuration = mmcConfiguration; if (inquiryData == null || !inquiry.HasValue) { return; } Visible = true; txtScsiInquiry.Text = Inquiry.Prettify(inquiry); if (mode.HasValue) { tabScsiModeSense.Visible = true; var modePagesList = new TreeGridItemCollection(); treeModeSensePages.Columns.Add(new GridColumn { HeaderText = "Page", DataCell = new TextBoxCell(0) }); treeModeSensePages.AllowMultipleSelection = false; treeModeSensePages.ShowHeader = false; treeModeSensePages.DataStore = modePagesList; modePagesList.Add(new TreeGridItem { Values = new object[] { "Header", Modes.PrettifyModeHeader(mode.Value.Header, type) } }); if (mode.Value.Pages != null) { foreach (var page in mode.Value.Pages.OrderBy(t => t.Page).ThenBy(t => t.Subpage)) { var pageNumberText = page.Subpage == 0 ? $"MODE {page.Page:X2}h" : $"MODE {page.Page:X2} Subpage {page.Subpage:X2}"; string decodedText; switch (page.Page) { case 0x00: { if (type == PeripheralDeviceTypes.MultiMediaDevice && page.Subpage == 0) { decodedText = Modes.PrettifyModePage_00_SFF(page.PageResponse); } else { decodedText = "Undecoded"; } break; } case 0x01: { if (page.Subpage == 0) { decodedText = type == PeripheralDeviceTypes.MultiMediaDevice ? Modes.PrettifyModePage_01_MMC(page.PageResponse) : Modes.PrettifyModePage_01(page.PageResponse); } else { goto default; } break; } case 0x02: { if (page.Subpage == 0) { decodedText = Modes.PrettifyModePage_02(page.PageResponse); } else { goto default; } break; } case 0x03: { if (page.Subpage == 0) { decodedText = Modes.PrettifyModePage_03(page.PageResponse); } else { goto default; } break; } case 0x04: { if (page.Subpage == 0) { decodedText = Modes.PrettifyModePage_04(page.PageResponse); } else { goto default; } break; } case 0x05: { if (page.Subpage == 0) { decodedText = Modes.PrettifyModePage_05(page.PageResponse); } else { goto default; } break; } case 0x06: { if (page.Subpage == 0) { decodedText = Modes.PrettifyModePage_06(page.PageResponse); } else { goto default; } break; } case 0x07: { if (page.Subpage == 0) { decodedText = type == PeripheralDeviceTypes.MultiMediaDevice ? Modes.PrettifyModePage_07_MMC(page.PageResponse) : Modes.PrettifyModePage_07(page.PageResponse); } else { goto default; } break; } case 0x08: { if (page.Subpage == 0) { decodedText = Modes.PrettifyModePage_08(page.PageResponse); } else { goto default; } break; } case 0x0A: { if (page.Subpage == 0) { decodedText = Modes.PrettifyModePage_0A(page.PageResponse); } else if (page.Subpage == 1) { decodedText = Modes.PrettifyModePage_0A_S01(page.PageResponse); } else { goto default; } break; } case 0x0B: { if (page.Subpage == 0) { decodedText = Modes.PrettifyModePage_0B(page.PageResponse); } else { goto default; } break; } case 0x0D: { if (page.Subpage == 0) { decodedText = Modes.PrettifyModePage_0D(page.PageResponse); } else { goto default; } break; } case 0x0E: { if (page.Subpage == 0) { decodedText = Modes.PrettifyModePage_0E(page.PageResponse); } else { goto default; } break; } case 0x0F: { if (page.Subpage == 0) { decodedText = Modes.PrettifyModePage_0F(page.PageResponse); } else { goto default; } break; } case 0x10: { if (page.Subpage == 0) { decodedText = type == PeripheralDeviceTypes.SequentialAccess ? Modes.PrettifyModePage_10_SSC(page.PageResponse) : Modes.PrettifyModePage_10(page.PageResponse); } else { goto default; } break; } case 0x11: { if (page.Subpage == 0) { decodedText = Modes.PrettifyModePage_11(page.PageResponse); } else { goto default; } break; } case 0x12: case 0x13: case 0x14: { if (page.Subpage == 0) { decodedText = Modes.PrettifyModePage_12_13_14(page.PageResponse); } else { goto default; } break; } case 0x1A: { if (page.Subpage == 0) { decodedText = Modes.PrettifyModePage_1A(page.PageResponse); } else if (page.Subpage == 1) { decodedText = Modes.PrettifyModePage_1A_S01(page.PageResponse); } else { goto default; } break; } case 0x1B: { if (page.Subpage == 0) { decodedText = Modes.PrettifyModePage_1B(page.PageResponse); } else { goto default; } break; } case 0x1C: { if (page.Subpage == 0) { decodedText = type == PeripheralDeviceTypes.MultiMediaDevice ? Modes.PrettifyModePage_1C_SFF(page.PageResponse) : Modes.PrettifyModePage_1C(page.PageResponse); } else if (page.Subpage == 1) { decodedText = Modes.PrettifyModePage_1C_S01(page.PageResponse); } else { goto default; } break; } case 0x1D: { if (page.Subpage == 0) { decodedText = Modes.PrettifyModePage_1D(page.PageResponse); } else { goto default; } break; } case 0x21: { if (StringHandlers.CToString(inquiry?.VendorIdentification).Trim() == "CERTANCE") { decodedText = Modes.PrettifyCertanceModePage_21(page.PageResponse); } else { goto default; } break; } case 0x22: { if (StringHandlers.CToString(inquiry?.VendorIdentification).Trim() == "CERTANCE") { decodedText = Modes.PrettifyCertanceModePage_22(page.PageResponse); } else { goto default; } break; } case 0x24: { if (StringHandlers.CToString(inquiry?.VendorIdentification).Trim() == "IBM") { decodedText = Modes.PrettifyIBMModePage_24(page.PageResponse); } else { goto default; } break; } case 0x2A: { if (page.Subpage == 0) { decodedText = Modes.PrettifyModePage_2A(page.PageResponse); } else { goto default; } break; } case 0x2F: { if (StringHandlers.CToString(inquiry?.VendorIdentification).Trim() == "IBM") { decodedText = Modes.PrettifyIBMModePage_2F(page.PageResponse); } else { goto default; } break; } case 0x30: { if (Modes.IsAppleModePage_30(page.PageResponse)) { decodedText = "Drive identifies as Apple OEM drive"; } else { goto default; } break; } case 0x3B: { if (StringHandlers.CToString(inquiry?.VendorIdentification).Trim() == "HP") { decodedText = Modes.PrettifyHPModePage_3B(page.PageResponse); } else { goto default; } break; } case 0x3C: { if (StringHandlers.CToString(inquiry?.VendorIdentification).Trim() == "HP") { decodedText = Modes.PrettifyHPModePage_3C(page.PageResponse); } else { goto default; } break; } case 0x3D: { if (StringHandlers.CToString(inquiry?.VendorIdentification).Trim() == "IBM") { decodedText = Modes.PrettifyIBMModePage_3D(page.PageResponse); } else if (StringHandlers.CToString(inquiry?.VendorIdentification).Trim() == "HP") { decodedText = Modes.PrettifyHPModePage_3D(page.PageResponse); } else { goto default; } break; } case 0x3E: { if (StringHandlers.CToString(inquiry?.VendorIdentification).Trim() == "FUJITSU") { decodedText = Modes.PrettifyFujitsuModePage_3E(page.PageResponse); } else if (StringHandlers.CToString(inquiry?.VendorIdentification).Trim() == "HP") { decodedText = Modes.PrettifyHPModePage_3E(page.PageResponse); } else { goto default; } break; } default: { decodedText = "Undecoded"; break; } } // TODO: Automatic error reporting if (decodedText == null) { decodedText = "Error decoding page, please open an issue."; } modePagesList.Add(new TreeGridItem { Values = new object[] { pageNumberText, decodedText } }); } } } if (evpdPages != null) { tabScsiEvpd.Visible = true; treeEvpdPages.ShowHeader = false; var evpdPagesList = new TreeGridItemCollection(); treeEvpdPages.Columns.Add(new GridColumn { HeaderText = "Page", DataCell = new TextBoxCell(0) }); treeEvpdPages.AllowMultipleSelection = false; treeEvpdPages.ShowHeader = false; treeEvpdPages.DataStore = evpdPagesList; foreach (var page in evpdPages.OrderBy(t => t.Key)) { var evpdPageTitle = ""; var evpdDecodedPage = ""; if (page.Key >= 0x01 && page.Key <= 0x7F) { evpdPageTitle = $"ASCII Page {page.Key:X2}h"; evpdDecodedPage = EVPD.DecodeASCIIPage(page.Value); } else if (page.Key == 0x80) { evpdPageTitle = "Unit Serial Number"; evpdDecodedPage = EVPD.DecodePage80(page.Value); } else if (page.Key == 0x81) { evpdPageTitle = "SCSI Implemented operating definitions"; evpdDecodedPage = EVPD.PrettifyPage_81(page.Value); } else if (page.Key == 0x82) { evpdPageTitle = "ASCII implemented operating definitions"; evpdDecodedPage = EVPD.DecodePage82(page.Value); } else if (page.Key == 0x83) { evpdPageTitle = "SCSI Device identification"; evpdDecodedPage = EVPD.PrettifyPage_83(page.Value); } else if (page.Key == 0x84) { evpdPageTitle = "SCSI Software Interface Identifiers"; evpdDecodedPage = EVPD.PrettifyPage_84(page.Value); } else if (page.Key == 0x85) { evpdPageTitle = "SCSI Management Network Addresses"; evpdDecodedPage = EVPD.PrettifyPage_85(page.Value); } else if (page.Key == 0x86) { evpdPageTitle = "SCSI Extended INQUIRY Data"; evpdDecodedPage = EVPD.PrettifyPage_86(page.Value); } else if (page.Key == 0x89) { evpdPageTitle = "SCSI to ATA Translation Layer Data"; evpdDecodedPage = EVPD.PrettifyPage_89(page.Value); } else if (page.Key == 0xB0) { evpdPageTitle = "SCSI Sequential-access Device Capabilities"; evpdDecodedPage = EVPD.PrettifyPage_B0(page.Value); } else if (page.Key == 0xB1) { evpdPageTitle = "Manufacturer-assigned Serial Number"; evpdDecodedPage = EVPD.DecodePageB1(page.Value); } else if (page.Key == 0xB2) { evpdPageTitle = "TapeAlert Supported Flags Bitmap"; evpdDecodedPage = $"0x{EVPD.DecodePageB2(page.Value):X16}"; } else if (page.Key == 0xB3) { evpdPageTitle = "Automation Device Serial Number"; evpdDecodedPage = EVPD.DecodePageB3(page.Value); } else if (page.Key == 0xB4) { evpdPageTitle = "Data Transfer Device Element Address"; evpdDecodedPage = EVPD.DecodePageB4(page.Value); } else if (page.Key == 0xC0 && StringHandlers.CToString(inquiry.Value.VendorIdentification).ToLowerInvariant().Trim() == "quantum") { evpdPageTitle = "Quantum Firmware Build Information page"; evpdDecodedPage = EVPD.PrettifyPage_C0_Quantum(page.Value); } else if (page.Key == 0xC0 && StringHandlers.CToString(inquiry.Value.VendorIdentification).ToLowerInvariant().Trim() == "seagate") { evpdPageTitle = "Seagate Firmware Numbers page"; evpdDecodedPage = EVPD.PrettifyPage_C0_Seagate(page.Value); } else if (page.Key == 0xC0 && StringHandlers.CToString(inquiry.Value.VendorIdentification).ToLowerInvariant().Trim() == "ibm") { evpdPageTitle = "IBM Drive Component Revision Levels page"; evpdDecodedPage = EVPD.PrettifyPage_C0_IBM(page.Value); } else if (page.Key == 0xC1 && StringHandlers.CToString(inquiry.Value.VendorIdentification).ToLowerInvariant().Trim() == "ibm") { evpdPageTitle = "IBM Drive Serial Numbers page"; evpdDecodedPage = EVPD.PrettifyPage_C1_IBM(page.Value); } else if ((page.Key == 0xC0 || page.Key == 0xC1) && StringHandlers.CToString(inquiry.Value.VendorIdentification).ToLowerInvariant().Trim() == "certance") { evpdPageTitle = "Certance Drive Component Revision Levels page"; evpdDecodedPage = EVPD.PrettifyPage_C0_C1_Certance(page.Value); } else if ((page.Key == 0xC2 || page.Key == 0xC3 || page.Key == 0xC4 || page.Key == 0xC5 || page.Key == 0xC6) && StringHandlers.CToString(inquiry.Value.VendorIdentification).ToLowerInvariant().Trim() == "certance") { switch (page.Key) { case 0xC2: evpdPageTitle = "Head Assembly Serial Number"; break; case 0xC3: evpdPageTitle = "Reel Motor 1 Serial Number"; break; case 0xC4: evpdPageTitle = "Reel Motor 2 Serial Number"; break; case 0xC5: evpdPageTitle = "Board Serial Number"; break; case 0xC6: evpdPageTitle = "Base Mechanical Serial Number"; break; } evpdDecodedPage = EVPD.PrettifyPage_C2_C3_C4_C5_C6_Certance(page.Value); } else if ((page.Key == 0xC0 || page.Key == 0xC1 || page.Key == 0xC2 || page.Key == 0xC3 || page.Key == 0xC4 || page.Key == 0xC5) && StringHandlers .CToString(inquiry.Value.VendorIdentification) .ToLowerInvariant().Trim() == "hp") { switch (page.Key) { case 0xC0: evpdPageTitle = "HP Drive Firmware Revision Levels page:"; break; case 0xC1: evpdPageTitle = "HP Drive Hardware Revision Levels page:"; break; case 0xC2: evpdPageTitle = "HP Drive PCA Revision Levels page:"; break; case 0xC3: evpdPageTitle = "HP Drive Mechanism Revision Levels page:"; break; case 0xC4: evpdPageTitle = "HP Drive Head Assembly Revision Levels page:"; break; case 0xC5: evpdPageTitle = "HP Drive ACI Revision Levels page:"; break; } evpdDecodedPage = EVPD.PrettifyPage_C0_to_C5_HP(page.Value); } else if (page.Key == 0xDF && StringHandlers.CToString(inquiry.Value.VendorIdentification).ToLowerInvariant().Trim() == "certance") { evpdPageTitle = "Certance drive status page"; evpdDecodedPage = EVPD.PrettifyPage_DF_Certance(page.Value); } else { if (page.Key == 0x00) { continue; } evpdPageTitle = $"Page {page.Key:X2}h"; evpdDecodedPage = "Undecoded"; DicConsole.DebugWriteLine("Device-Info command", "Found undecoded SCSI VPD page 0x{0:X2}", page.Key); } evpdPagesList.Add(new TreeGridItem { Values = new object[] { evpdPageTitle, evpdDecodedPage, page.Value } }); } } if (configuration != null) { tabMmcFeatures.Visible = true; var featuresList = new TreeGridItemCollection(); treeMmcFeatures.Columns.Add(new GridColumn { HeaderText = "Feature", DataCell = new TextBoxCell(0) }); treeMmcFeatures.AllowMultipleSelection = false; treeMmcFeatures.ShowHeader = false; treeMmcFeatures.DataStore = featuresList; var ftr = Features.Separate(configuration); DicConsole.DebugWriteLine("Device-Info command", "GET CONFIGURATION length is {0} bytes", ftr.DataLength); DicConsole.DebugWriteLine("Device-Info command", "GET CONFIGURATION current profile is {0:X4}h", ftr.CurrentProfile); if (ftr.Descriptors != null) { foreach (var desc in ftr.Descriptors) { var featureNumber = $"Feature {desc.Code:X4}h"; string featureDescription; DicConsole.DebugWriteLine("Device-Info command", "Feature {0:X4}h", desc.Code); switch (desc.Code) { case 0x0000: featureDescription = Features.Prettify_0000(desc.Data); break; case 0x0001: featureDescription = Features.Prettify_0001(desc.Data); break; case 0x0002: featureDescription = Features.Prettify_0002(desc.Data); break; case 0x0003: featureDescription = Features.Prettify_0003(desc.Data); break; case 0x0004: featureDescription = Features.Prettify_0004(desc.Data); break; case 0x0010: featureDescription = Features.Prettify_0010(desc.Data); break; case 0x001D: featureDescription = Features.Prettify_001D(desc.Data); break; case 0x001E: featureDescription = Features.Prettify_001E(desc.Data); break; case 0x001F: featureDescription = Features.Prettify_001F(desc.Data); break; case 0x0020: featureDescription = Features.Prettify_0020(desc.Data); break; case 0x0021: featureDescription = Features.Prettify_0021(desc.Data); break; case 0x0022: featureDescription = Features.Prettify_0022(desc.Data); break; case 0x0023: featureDescription = Features.Prettify_0023(desc.Data); break; case 0x0024: featureDescription = Features.Prettify_0024(desc.Data); break; case 0x0025: featureDescription = Features.Prettify_0025(desc.Data); break; case 0x0026: featureDescription = Features.Prettify_0026(desc.Data); break; case 0x0027: featureDescription = Features.Prettify_0027(desc.Data); break; case 0x0028: featureDescription = Features.Prettify_0028(desc.Data); break; case 0x0029: featureDescription = Features.Prettify_0029(desc.Data); break; case 0x002A: featureDescription = Features.Prettify_002A(desc.Data); break; case 0x002B: featureDescription = Features.Prettify_002B(desc.Data); break; case 0x002C: featureDescription = Features.Prettify_002C(desc.Data); break; case 0x002D: featureDescription = Features.Prettify_002D(desc.Data); break; case 0x002E: featureDescription = Features.Prettify_002E(desc.Data); break; case 0x002F: featureDescription = Features.Prettify_002F(desc.Data); break; case 0x0030: featureDescription = Features.Prettify_0030(desc.Data); break; case 0x0031: featureDescription = Features.Prettify_0031(desc.Data); break; case 0x0032: featureDescription = Features.Prettify_0032(desc.Data); break; case 0x0033: featureDescription = Features.Prettify_0033(desc.Data); break; case 0x0035: featureDescription = Features.Prettify_0035(desc.Data); break; case 0x0037: featureDescription = Features.Prettify_0037(desc.Data); break; case 0x0038: featureDescription = Features.Prettify_0038(desc.Data); break; case 0x003A: featureDescription = Features.Prettify_003A(desc.Data); break; case 0x003B: featureDescription = Features.Prettify_003B(desc.Data); break; case 0x0040: featureDescription = Features.Prettify_0040(desc.Data); break; case 0x0041: featureDescription = Features.Prettify_0041(desc.Data); break; case 0x0042: featureDescription = Features.Prettify_0042(desc.Data); break; case 0x0050: featureDescription = Features.Prettify_0050(desc.Data); break; case 0x0051: featureDescription = Features.Prettify_0051(desc.Data); break; case 0x0080: featureDescription = Features.Prettify_0080(desc.Data); break; case 0x0100: featureDescription = Features.Prettify_0100(desc.Data); break; case 0x0101: featureDescription = Features.Prettify_0101(desc.Data); break; case 0x0102: featureDescription = Features.Prettify_0102(desc.Data); break; case 0x0103: featureDescription = Features.Prettify_0103(desc.Data); break; case 0x0104: featureDescription = Features.Prettify_0104(desc.Data); break; case 0x0105: featureDescription = Features.Prettify_0105(desc.Data); break; case 0x0106: featureDescription = Features.Prettify_0106(desc.Data); break; case 0x0107: featureDescription = Features.Prettify_0107(desc.Data); break; case 0x0108: featureDescription = Features.Prettify_0108(desc.Data); break; case 0x0109: featureDescription = Features.Prettify_0109(desc.Data); break; case 0x010A: featureDescription = Features.Prettify_010A(desc.Data); break; case 0x010B: featureDescription = Features.Prettify_010B(desc.Data); break; case 0x010C: featureDescription = Features.Prettify_010C(desc.Data); break; case 0x010D: featureDescription = Features.Prettify_010D(desc.Data); break; case 0x010E: featureDescription = Features.Prettify_010E(desc.Data); break; case 0x0110: featureDescription = Features.Prettify_0110(desc.Data); break; case 0x0113: featureDescription = Features.Prettify_0113(desc.Data); break; case 0x0142: featureDescription = Features.Prettify_0142(desc.Data); break; default: featureDescription = "Unknown feature"; break; } featuresList.Add(new TreeGridItem { Values = new object[] { featureNumber, featureDescription } }); } } else { DicConsole.DebugWriteLine("Device-Info command", "GET CONFIGURATION returned no feature descriptors"); } } Invalidate(); }