/* Copyright (C) 2012-2017 Tal Aloni . All rights reserved. * * You can redistribute this program and/or modify it under the terms of * the GNU Lesser Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. */ using System; using System.Collections.Generic; using System.Text; using Utilities; namespace SCSI { public class StandardInquiryData { public byte PeripheralQualifier; public PeripheralDeviceType PeripheralDeviceType; public bool RMB; // Removable media bit public byte Version; // We only support Version == 2 public bool NormACA; // Normal ACA Supported public bool HiSup; // Hierarchical Support public byte ResponseDataFormat; public byte AdditionalLength; // Number of bytes following this byte public bool SCCS; // SCC Supported public bool ACC; // Access Controls Coordinator public byte TPGS; // Target Port Group Support public bool ThirdPartyCopy; // 3PC public bool Protect; public bool EncServ; // Enclosure Services public bool VS1; // Vendor specific public bool MultiP; // Multi Port public bool MChngr; // Medium Changer public bool Addr16; // Indicates that the SCSI target device supports 16-bit wide SCSI addresses public bool WBus16; // Indicates that the SCSI target device supports 16-bit wide data transfers public bool Sync; // Indicates that the SCSI target device supports synchronous data transfer public bool CmdQue; // Command Queuing public bool VS2; // Vendor specific /// /// 8 characters /// public string VendorIdentification; /// /// 16 characters /// public string ProductIdentification; /// /// 4 characters /// public string ProductRevisionLevel; public ulong DriveSerialNumber; // Vendor Unique public byte Clocking; public bool QAS; public bool IUS; public List VersionDescriptors = new List(); // 8 descriptors (16 bytes) public StandardInquiryData() { ResponseDataFormat = 2; AdditionalLength = 91; } public StandardInquiryData(byte[] buffer, int offset) { PeripheralQualifier = (byte)(buffer[offset + 0] >> 5); PeripheralDeviceType = (PeripheralDeviceType)(buffer[offset + 0] & 0x1F); RMB = (buffer[offset + 1] & 0x80) != 0; Version = buffer[offset + 2]; if (Version != 2) { return; } NormACA = (buffer[offset + 3] & 0x20) != 0; HiSup = (buffer[offset + 3] & 0x10) != 0; ResponseDataFormat = (byte)(buffer[offset + 3] & 0x0F); AdditionalLength = buffer[offset + 4]; if (AdditionalLength < 91) // Standard Inquiry data should be at least 96 bytes (so the AdditionalLength must be at least 96 - 5) { return; } SCCS = (buffer[offset + 5] & 0x80) != 0; ACC = (buffer[offset + 5] & 0x40) != 0; TPGS = (byte)((buffer[offset + 5] >> 4) & 0x03); ThirdPartyCopy = (buffer[offset + 5] & 0x08) != 0; Protect = (buffer[offset + 5] & 0x01) != 0; EncServ = (buffer[offset + 6] & 0x40) != 0; VS1 = (buffer[offset + 6] & 0x20) != 0; MultiP = (buffer[offset + 6] & 0x10) != 0; MChngr = (buffer[offset + 6] & 0x08) != 0; Addr16 = (buffer[offset + 6] & 0x01) != 0; WBus16 = (buffer[offset + 7] & 0x20) != 0; Sync = (buffer[offset + 7] & 0x10) != 0; CmdQue = (buffer[offset + 7] & 0x02) != 0; VS2 = (buffer[offset + 7] & 0x01) != 0; VendorIdentification = Encoding.ASCII.GetString(buffer, 8, 8); ProductIdentification = Encoding.ASCII.GetString(buffer, 16, 16); ProductRevisionLevel = Encoding.ASCII.GetString(buffer, 32, 4); DriveSerialNumber = BigEndianConverter.ToUInt64(buffer, 36); Clocking = (byte)((buffer[offset + 56] >> 2) & 0x03); QAS = (buffer[offset + 56] & 0x02) != 0; IUS = (buffer[offset + 56] & 0x01) != 0; for (int index = 0; index < 8; index++) { VersionDescriptorName versionDescriptor = (VersionDescriptorName)BigEndianConverter.ToUInt16(buffer, offset + 58 + index * 2); VersionDescriptors.Add(versionDescriptor); } } public byte[] GetBytes() { byte[] buffer = new byte[96]; buffer[0] |= (byte)(PeripheralQualifier << 5); buffer[0] |= (byte)(PeripheralQualifier & 0x1F); if (RMB) { buffer[1] |= 0x80; } buffer[2] = Version; if (NormACA) { buffer[3] |= 0x20; } if (HiSup) { buffer[3] |= 0x10; } buffer[3] |= (byte)(ResponseDataFormat & 0x0F); buffer[4] = AdditionalLength; if (SCCS) { buffer[5] |= 0x80; } if (ACC) { buffer[5] |= 0x40; } buffer[5] |= (byte)((TPGS & 0x03) << 4); if (ThirdPartyCopy) { buffer[5] |= 0x08; } if (Protect) { buffer[5] |= 0x01; } if (EncServ) { buffer[6] |= 0x40; } if (VS1) { buffer[6] |= 0x20; } if (MultiP) { buffer[6] |= 0x10; } if (MChngr) { buffer[6] |= 0x08; } if (Addr16) { buffer[6] |= 0x01; } if (WBus16) { buffer[7] |= 0x20; } if (Sync) { buffer[7] |= 0x10; } if (CmdQue) { buffer[7] |= 0x02; } if (VS2) { buffer[7] |= 0x01; } ByteWriter.WriteAnsiString(buffer, 8, VendorIdentification, 8); ByteWriter.WriteAnsiString(buffer, 16, ProductIdentification, 16); ByteWriter.WriteAnsiString(buffer, 32, ProductRevisionLevel, 4); BigEndianWriter.WriteUInt64(buffer, 36, DriveSerialNumber); buffer[56] |= (byte)((Clocking & 0x03) << 2); if (QAS) { buffer[56] |= 0x02; } if (IUS) { buffer[56] |= 0x01; } for (int index = 0; index < 8; index++) { ushort versionDescriptor = 0; if (index < VersionDescriptors.Count) { versionDescriptor = (ushort)VersionDescriptors[index]; } BigEndianWriter.WriteUInt16(buffer, 58 + index * 2, versionDescriptor); } return buffer; } } }