public bool ReadNativeMaxAddress(out uint lba, out AtaErrorRegistersLba28 statusRegisters, uint timeout, out double duration) { lba = 0; byte[] buffer = new byte[0]; AtaRegistersLba28 registers = new AtaRegistersLba28 { Command = (byte)AtaCommands.ReadNativeMaxAddress }; registers.DeviceHead += 0x40; LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.NonData, AtaTransferRegister.NoTransfer, ref buffer, timeout, false, out duration, out bool sense); Error = LastError != 0; if ((statusRegisters.Status & 0x23) == 0) { lba += (uint)(statusRegisters.DeviceHead & 0xF); lba *= 0x1000000; lba += (uint)(statusRegisters.LbaHigh << 16); lba += (uint)(statusRegisters.LbaMid << 8); lba += statusRegisters.LbaLow; } DicConsole.DebugWriteLine("ATA Device", "READ NATIVE MAX ADDRESS took {0} ms.", duration); return(sense); }
public bool TranslateSector(out byte[] buffer, out AtaErrorRegistersLba28 statusRegisters, uint lba, uint timeout, out double duration) { buffer = new byte[512]; var registers = new AtaRegistersLba28 { Command = (byte)AtaCommands.TranslateSector, DeviceHead = (byte)((lba & 0xF000000) / 0x1000000), LbaHigh = (byte)((lba & 0xFF0000) / 0x10000), LbaMid = (byte)((lba & 0xFF00) / 0x100), LbaLow = (byte)((lba & 0xFF) / 0x1) }; registers.DeviceHead += 0x40; LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.PioIn, AtaTransferRegister.NoTransfer, ref buffer, timeout, false, out duration, out bool sense); Error = LastError != 0; AaruConsole.DebugWriteLine("ATA Device", "CFA TRANSLATE SECTOR took {0} ms.", duration); return(sense); }
public bool ReadLong(out byte[] buffer, out AtaErrorRegistersLba28 statusRegisters, bool retry, uint lba, uint blockSize, uint timeout, out double duration) { buffer = new byte[blockSize]; AtaRegistersLba28 registers = new AtaRegistersLba28 { SectorCount = 1, DeviceHead = (byte)((lba & 0xF000000) / 0x1000000), LbaHigh = (byte)((lba & 0xFF0000) / 0x10000), LbaMid = (byte)((lba & 0xFF00) / 0x100), LbaLow = (byte)((lba & 0xFF) / 0x1), Command = retry ? (byte)AtaCommands.ReadLongRetry : (byte)AtaCommands.ReadLong }; registers.DeviceHead += 0x40; LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.PioIn, AtaTransferRegister.SectorCount, ref buffer, timeout, true, out duration, out bool sense); Error = LastError != 0; DicConsole.DebugWriteLine("ATA Device", "READ LONG took {0} ms.", duration); return(sense); }
public bool Seek(out AtaErrorRegistersLba28 statusRegisters, uint lba, uint timeout, out double duration) { byte[] buffer = new byte[0]; var registers = new AtaRegistersLba28 { Command = (byte)AtaCommands.Seek, DeviceHead = (byte)((lba & 0xF000000) / 0x1000000), LbaHigh = (byte)((lba & 0xFF0000) / 0x10000), LbaMid = (byte)((lba & 0xFF00) / 0x100), LbaLow = (byte)((lba & 0xFF) / 0x1) }; registers.DeviceHead += 0x40; LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.NonData, AtaTransferRegister.NoTransfer, ref buffer, timeout, false, out duration, out bool sense); Error = LastError != 0; AaruConsole.DebugWriteLine("ATA Device", "SEEK took {0} ms.", duration); return(sense); }
public bool ReadMultiple(out byte[] buffer, out AtaErrorRegistersLba28 statusRegisters, uint lba, byte count, uint timeout, out double duration) { buffer = count == 0 ? new byte[512 * 256] : new byte[512 * count]; AtaRegistersLba28 registers = new AtaRegistersLba28 { Command = (byte)AtaCommands.ReadMultiple, SectorCount = count, DeviceHead = (byte)((lba & 0xF000000) / 0x1000000), LbaHigh = (byte)((lba & 0xFF0000) / 0x10000), LbaMid = (byte)((lba & 0xFF00) / 0x100), LbaLow = (byte)((lba & 0xFF) / 0x1) }; registers.DeviceHead += 0x40; LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.PioIn, AtaTransferRegister.SectorCount, ref buffer, timeout, true, out duration, out bool sense); Error = LastError != 0; DicConsole.DebugWriteLine("ATA Device", "READ MULTIPLE took {0} ms.", duration); return(sense); }
public bool ReadDma(out byte[] buffer, out AtaErrorRegistersLba28 statusRegisters, bool retry, uint lba, byte count, uint timeout, out double duration) { buffer = count == 0 ? new byte[512 * 256] : new byte[512 * count]; var registers = new AtaRegistersLba28 { SectorCount = count, DeviceHead = (byte)((lba & 0xF000000) / 0x1000000), LbaHigh = (byte)((lba & 0xFF0000) / 0x10000), LbaMid = (byte)((lba & 0xFF00) / 0x100), LbaLow = (byte)((lba & 0xFF) / 0x1), Command = retry ? (byte)AtaCommands.ReadDmaRetry : (byte)AtaCommands.ReadDma }; registers.DeviceHead += 0x40; LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.Dma, AtaTransferRegister.SectorCount, ref buffer, timeout, true, out duration, out bool sense); Error = LastError != 0; AaruConsole.DebugWriteLine("ATA Device", "READ DMA took {0} ms.", duration); return(sense); }
/// <summary> /// Sends an ATA/ATAPI command to this device using 28-bit LBA addressing /// </summary> /// <returns>0 if no error occurred, otherwise, errno</returns> /// <param name="registers">ATA registers.</param> /// <param name="errorRegisters">Status/error registers.</param> /// <param name="protocol">ATA Protocol.</param> /// <param name="transferRegister">Indicates which register indicates the transfer length</param> /// <param name="buffer">Buffer for ATA/ATAPI command response</param> /// <param name="timeout">Timeout in seconds</param> /// <param name="transferBlocks"> /// If set to <c>true</c>, transfer is indicated in blocks, otherwise, it is indicated in /// bytes. /// </param> /// <param name="duration">Time it took to execute the command in milliseconds</param> /// <param name="sense"><c>True</c> if ATA/ATAPI command returned non-OK status</param> public int SendAtaCommand(AtaRegistersLba28 registers, out AtaErrorRegistersLba28 errorRegisters, AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer, uint timeout, bool transferBlocks, out double duration, out bool sense) => Command.SendAtaCommand(PlatformId, FileHandle, registers, out errorRegisters, protocol, transferRegister, ref buffer, timeout, transferBlocks, out duration, out sense);
/// <summary>Sends an ATA command in CHS format</summary> /// <returns>0 if no error occurred, otherwise, errno</returns> /// <param name="fd">File handle</param> /// <param name="buffer">Buffer for SCSI command response</param> /// <param name="timeout">Timeout in seconds</param> /// <param name="duration">Time it took to execute the command in milliseconds</param> /// <param name="sense"><c>True</c> if ATA returned non-OK status</param> /// <param name="registers">Registers to send to the device</param> /// <param name="errorRegisters">Registers returned by the device</param> /// <param name="protocol">ATA protocol to use</param> /// <param name="transferRegister">What register contains the transfer length</param> /// <param name="transferBlocks">Set to <c>true</c> if the transfer length is in block, otherwise it is in bytes</param> /// <exception cref="InvalidOperationException">If the specified platform is not supported</exception> internal static int SendAtaCommand(object fd, AtaRegistersLba28 registers, out AtaErrorRegistersLba28 errorRegisters, AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer, uint timeout, bool transferBlocks, out double duration, out bool sense) { PlatformID ptId = DetectOS.GetRealPlatformID(); return(SendAtaCommand(ptId, fd, registers, out errorRegisters, protocol, transferRegister, ref buffer, timeout, transferBlocks, out duration, out sense)); }
/// <summary>Sends an ATA/ATAPI command to this device using 28-bit LBA addressing</summary> /// <returns>0 if no error occurred, otherwise, errno</returns> /// <param name="registers">ATA registers.</param> /// <param name="errorRegisters">Status/error registers.</param> /// <param name="protocol">ATA Protocol.</param> /// <param name="transferRegister">Indicates which register indicates the transfer length</param> /// <param name="buffer">Buffer for ATA/ATAPI command response</param> /// <param name="timeout">Timeout in seconds</param> /// <param name="transferBlocks"> /// If set to <c>true</c>, transfer is indicated in blocks, otherwise, it is indicated in /// bytes. /// </param> /// <param name="duration">Time it took to execute the command in milliseconds</param> /// <param name="sense"><c>True</c> if ATA/ATAPI command returned non-OK status</param> public int SendAtaCommand(AtaRegistersLba28 registers, out AtaErrorRegistersLba28 errorRegisters, AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer, uint timeout, bool transferBlocks, out double duration, out bool sense) { if (!(_remote is null)) { return(_remote.SendAtaCommand(registers, out errorRegisters, protocol, transferRegister, ref buffer, timeout, transferBlocks, out duration, out sense)); } return(Command.SendAtaCommand(PlatformId, FileHandle, registers, out errorRegisters, protocol, transferRegister, ref buffer, timeout, transferBlocks, out duration, out sense)); }
public bool ReadBufferDma(out byte[] buffer, out AtaErrorRegistersLba28 statusRegisters, uint timeout, out double duration) { buffer = new byte[512]; AtaRegistersLba28 registers = new AtaRegistersLba28 { Command = (byte)AtaCommands.ReadBufferDma }; LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.Dma, AtaTransferRegister.NoTransfer, ref buffer, timeout, false, out duration, out bool sense); Error = LastError != 0; DicConsole.DebugWriteLine("ATA Device", "READ BUFFER DMA took {0} ms.", duration); return(sense); }
public static string DecodeAtaRegisters(AtaErrorRegistersLba28 registers) { StringBuilder sb = new StringBuilder(); sb.AppendFormat("Status: {0}", DecodeAtaStatus(registers.Status)).AppendLine(); sb.AppendFormat("Error: {0}", DecodeAtaStatus(registers.Error)).AppendLine(); sb.AppendFormat("Device: {0}", (registers.DeviceHead >> 4) & 0x01).AppendLine(); sb.AppendFormat("LBA: {0}", ((registers.DeviceHead & 0xF) << 24) + (registers.LbaHigh << 16) + (registers.LbaMid << 8) + registers.LbaLow); sb.AppendFormat("Count: {0}", registers.SectorCount).AppendLine(); sb.AppendFormat("LBA?: {0}", Convert.ToBoolean(registers.DeviceHead & 0x40)).AppendLine(); sb.AppendFormat("Bit 7 set?: {0}", Convert.ToBoolean(registers.DeviceHead & 0x80)).AppendLine(); sb.AppendFormat("Bit 5 set?: {0}", Convert.ToBoolean(registers.DeviceHead & 0x20)).AppendLine(); return(sb.ToString()); }
/// <summary> /// Sends an ATA command in 28-bit LBA format /// </summary> /// <returns>0 if no error occurred, otherwise, errno</returns> /// <param name="ptId">Platform ID for executing the command</param> /// <param name="fd">File handle</param> /// <param name="buffer">Buffer for SCSI command response</param> /// <param name="timeout">Timeout in seconds</param> /// <param name="duration">Time it took to execute the command in milliseconds</param> /// <param name="sense"><c>True</c> if ATA returned non-OK status</param> /// <param name="registers">Registers to send to the device</param> /// <param name="errorRegisters">Registers returned by the device</param> /// <param name="protocol">ATA protocol to use</param> /// <param name="transferRegister">What register contains the transfer length</param> /// <param name="transferBlocks">Set to <c>true</c> if the transfer length is in block, otherwise it is in bytes</param> /// <exception cref="InvalidOperationException">If the specified platform is not supported</exception> internal static int SendAtaCommand(PlatformID ptId, object fd, AtaRegistersLba28 registers, out AtaErrorRegistersLba28 errorRegisters, AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer, uint timeout, bool transferBlocks, out double duration, out bool sense) { switch (ptId) { case PlatformID.Win32NT: { if (Environment.OSVersion.Version.Major == 5 && Environment.OSVersion.Version.Minor == 1 && (Environment.OSVersion.ServicePack == "Service Pack 1" || Environment.OSVersion.ServicePack == "") || Environment.OSVersion.Version.Major == 5 && Environment.OSVersion.Version.Minor == 0) { throw new InvalidOperationException("Windows XP or earlier is not supported."); } // Windows NT 4 or earlier, requires special ATA pass thru SCSI. But DiscImageChef cannot run there (or can it?) if (Environment.OSVersion.Version.Major <= 4) { throw new InvalidOperationException("Windows NT 4.0 or earlier is not supported."); } return(Windows.Command.SendAtaCommand((SafeFileHandle)fd, registers, out errorRegisters, protocol, ref buffer, timeout, out duration, out sense)); } case PlatformID.Linux: { return(Linux.Command.SendAtaCommand((int)fd, registers, out errorRegisters, protocol, transferRegister, ref buffer, timeout, transferBlocks, out duration, out sense)); } case PlatformID.FreeBSD: { return(FreeBSD.Command.SendAtaCommand((IntPtr)fd, registers, out errorRegisters, protocol, ref buffer, timeout, out duration, out sense)); } default: throw new InvalidOperationException($"Platform {ptId} not yet supported."); } }
public bool RequestExtendedErrorCode(out byte errorCode, out AtaErrorRegistersLba28 statusRegisters, uint timeout, out double duration) { byte[] buffer = new byte[0]; AtaRegistersLba28 registers = new AtaRegistersLba28 { Command = (byte)AtaCommands.RequestSense }; LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.PioIn, AtaTransferRegister.NoTransfer, ref buffer, timeout, false, out duration, out bool sense); Error = LastError != 0; errorCode = statusRegisters.Error; DicConsole.DebugWriteLine("ATA Device", "CFA REQUEST EXTENDED ERROR CODE took {0} ms.", duration); return(sense); }
public bool SmartDisable(out AtaErrorRegistersLba28 statusRegisters, uint timeout, out double duration) { byte[] buffer = new byte[0]; AtaRegistersLba28 registers = new AtaRegistersLba28 { Command = (byte)AtaCommands.Smart, Feature = (byte)AtaSmartSubCommands.Disable, LbaHigh = 0xC2, LbaMid = 0x4F }; LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.NonData, AtaTransferRegister.NoTransfer, ref buffer, timeout, false, out duration, out bool sense); Error = LastError != 0; DicConsole.DebugWriteLine("ATA Device", "SMART DISABLE OPERATIONS took {0} ms.", duration); return(sense); }
public bool SmartEnableAttributeAutosave(out AtaErrorRegistersLba28 statusRegisters, uint timeout, out double duration) { byte[] buffer = new byte[0]; var registers = new AtaRegistersLba28 { Command = (byte)AtaCommands.Smart, Feature = (byte)AtaSmartSubCommands.EnableDisableAttributeAutosave, LbaHigh = 0xC2, LbaMid = 0x4F, SectorCount = 0xF1 }; LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.NonData, AtaTransferRegister.NoTransfer, ref buffer, timeout, false, out duration, out bool sense); Error = LastError != 0; AaruConsole.DebugWriteLine("ATA Device", "SMART ENABLE ATTRIBUTE AUTOSAVE took {0} ms.", duration); return(sense); }
public bool SmartExecuteOffLineImmediate(out AtaErrorRegistersLba28 statusRegisters, byte subcommand, uint timeout, out double duration) { byte[] buffer = new byte[0]; var registers = new AtaRegistersLba28 { Command = (byte)AtaCommands.Smart, Feature = (byte)AtaSmartSubCommands.ExecuteOfflineImmediate, LbaHigh = 0xC2, LbaMid = 0x4F, LbaLow = subcommand }; LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.NonData, AtaTransferRegister.NoTransfer, ref buffer, timeout, false, out duration, out bool sense); Error = LastError != 0; AaruConsole.DebugWriteLine("ATA Device", "SMART EXECUTE OFF-LINE IMMEDIATE took {0} ms.", duration); return(sense); }
public bool SmartReadLog(out byte[] buffer, out AtaErrorRegistersLba28 statusRegisters, byte logAddress, uint timeout, out double duration) { buffer = new byte[512]; var registers = new AtaRegistersLba28 { Command = (byte)AtaCommands.Smart, Feature = (byte)AtaSmartSubCommands.ReadLog, LbaHigh = 0xC2, LbaMid = 0x4F, LbaLow = logAddress }; LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.PioIn, AtaTransferRegister.NoTransfer, ref buffer, timeout, false, out duration, out bool sense); Error = LastError != 0; AaruConsole.DebugWriteLine("ATA Device", "SMART READ LOG took {0} ms.", duration); return(sense); }
/// <summary> /// Sends an ATA command in 28-bit LBA mode using undocumented Windows XP ioctl /// </summary> /// <returns>0 if no error occurred, otherwise, errno</returns> /// <param name="fd">File handle</param> /// <param name="buffer">Buffer for SCSI command response</param> /// <param name="timeout">Timeout in seconds</param> /// <param name="duration">Time it took to execute the command in milliseconds</param> /// <param name="sense"><c>True</c> if ATA error returned non-OK status</param> /// <param name="registers">Registers to send to drive</param> /// <param name="errorRegisters">Registers returned by drive</param> /// <param name="protocol">ATA protocol to use</param> internal static int SendIdeCommand(SafeFileHandle fd, AtaRegistersLba28 registers, out AtaErrorRegistersLba28 errorRegisters, AtaProtocol protocol, ref byte[] buffer, uint timeout, out double duration, out bool sense) { duration = 0; sense = false; errorRegisters = new AtaErrorRegistersLba28(); if (buffer == null) { return(-1); } IdePassThroughDirect iptd = new IdePassThroughDirect { CurrentTaskFile = new AtaTaskFile { Command = registers.Command, CylinderHigh = registers.LbaHigh, CylinderLow = registers.LbaMid, DeviceHead = registers.DeviceHead, Features = registers.Feature, SectorCount = registers.SectorCount, SectorNumber = registers.LbaLow }, DataBufferSize = 512, DataBuffer = new byte[512] }; uint k = 0; int error = 0; Array.Copy(buffer, 0, iptd.DataBuffer, 0, buffer.Length); DateTime start = DateTime.Now; sense = !Extern.DeviceIoControlIde(fd, WindowsIoctl.IoctlIdePassThrough, ref iptd, (uint)Marshal.SizeOf(iptd), ref iptd, (uint)Marshal.SizeOf(iptd), ref k, IntPtr.Zero); DateTime end = DateTime.Now; if (sense) { error = Marshal.GetLastWin32Error(); } buffer = new byte[k - 12]; Array.Copy(iptd.DataBuffer, 0, buffer, 0, buffer.Length); duration = (end - start).TotalMilliseconds; errorRegisters.LbaHigh = iptd.CurrentTaskFile.CylinderHigh; errorRegisters.LbaMid = iptd.CurrentTaskFile.CylinderLow; errorRegisters.DeviceHead = iptd.CurrentTaskFile.DeviceHead; errorRegisters.Error = iptd.CurrentTaskFile.Error; errorRegisters.LbaLow = iptd.CurrentTaskFile.SectorNumber; errorRegisters.SectorCount = iptd.CurrentTaskFile.SectorCount; errorRegisters.Status = iptd.CurrentTaskFile.Status; sense = errorRegisters.Error != 0 || (errorRegisters.Status & 0xA5) != 0; return(error); }
/// <summary> /// Sends an ATA command in 28-bit LBA mode /// </summary> /// <returns>0 if no error occurred, otherwise, errno</returns> /// <param name="fd">File handle</param> /// <param name="buffer">Buffer for SCSI command response</param> /// <param name="timeout">Timeout in seconds</param> /// <param name="duration">Time it took to execute the command in milliseconds</param> /// <param name="sense"><c>True</c> if ATA error returned non-OK status</param> /// <param name="registers">Registers to send to drive</param> /// <param name="errorRegisters">Registers returned by drive</param> /// <param name="protocol">ATA protocol to use</param> internal static int SendAtaCommand(SafeFileHandle fd, AtaRegistersLba28 registers, out AtaErrorRegistersLba28 errorRegisters, AtaProtocol protocol, ref byte[] buffer, uint timeout, out double duration, out bool sense) { duration = 0; sense = false; errorRegisters = new AtaErrorRegistersLba28(); if (buffer == null) { return(-1); } uint offsetForBuffer = (uint)(Marshal.SizeOf(typeof(AtaPassThroughDirect)) + Marshal.SizeOf(typeof(uint))); AtaPassThroughDirectWithBuffer aptdBuf = new AtaPassThroughDirectWithBuffer { aptd = new AtaPassThroughDirect { TimeOutValue = timeout, DataBuffer = (IntPtr)offsetForBuffer, Length = (ushort)Marshal.SizeOf(typeof(AtaPassThroughDirect)), DataTransferLength = (uint)buffer.Length, PreviousTaskFile = new AtaTaskFile(), CurrentTaskFile = new AtaTaskFile { Command = registers.Command, CylinderHigh = registers.LbaHigh, CylinderLow = registers.LbaMid, DeviceHead = registers.DeviceHead, Features = registers.Feature, SectorCount = registers.SectorCount, SectorNumber = registers.LbaLow } }, dataBuffer = new byte[64 * 512] }; switch (protocol) { case AtaProtocol.PioIn: case AtaProtocol.UDmaIn: case AtaProtocol.Dma: aptdBuf.aptd.AtaFlags = AtaFlags.DataIn; break; case AtaProtocol.PioOut: case AtaProtocol.UDmaOut: aptdBuf.aptd.AtaFlags = AtaFlags.DataOut; break; } switch (protocol) { case AtaProtocol.Dma: case AtaProtocol.DmaQueued: case AtaProtocol.FpDma: case AtaProtocol.UDmaIn: case AtaProtocol.UDmaOut: aptdBuf.aptd.AtaFlags |= AtaFlags.Dma; break; } // Unknown if needed aptdBuf.aptd.AtaFlags |= AtaFlags.DrdyRequired; uint k = 0; int error = 0; Array.Copy(buffer, 0, aptdBuf.dataBuffer, 0, buffer.Length); DateTime start = DateTime.Now; sense = !Extern.DeviceIoControlAta(fd, WindowsIoctl.IoctlAtaPassThrough, ref aptdBuf, (uint)Marshal.SizeOf(aptdBuf), ref aptdBuf, (uint)Marshal.SizeOf(aptdBuf), ref k, IntPtr.Zero); DateTime end = DateTime.Now; if (sense) { error = Marshal.GetLastWin32Error(); } Array.Copy(aptdBuf.dataBuffer, 0, buffer, 0, buffer.Length); duration = (end - start).TotalMilliseconds; errorRegisters.LbaHigh = aptdBuf.aptd.CurrentTaskFile.CylinderHigh; errorRegisters.LbaMid = aptdBuf.aptd.CurrentTaskFile.CylinderLow; errorRegisters.DeviceHead = aptdBuf.aptd.CurrentTaskFile.DeviceHead; errorRegisters.Error = aptdBuf.aptd.CurrentTaskFile.Error; errorRegisters.LbaLow = aptdBuf.aptd.CurrentTaskFile.SectorNumber; errorRegisters.SectorCount = aptdBuf.aptd.CurrentTaskFile.SectorCount; errorRegisters.Status = aptdBuf.aptd.CurrentTaskFile.Status; sense = errorRegisters.Error != 0 || (errorRegisters.Status & 0xA5) != 0; return(error); }
/// <summary>Register an ATA error after trying to read using 28-bit LBA commands</summary> /// <param name="block">Starting block</param> /// <param name="osError"><c>true</c> if operating system returned an error status instead of the device</param> /// <param name="errno">Operating system error number</param> /// <param name="registers">Error registers</param> public void WriteLine(ulong block, bool osError, int errno, AtaErrorRegistersLba28 registers) { if (osError) { _logSw.WriteLine("ATA reading LBA {0} operating system error: {1}.", block, errno); _logSw.Flush(); } else { List <string> error = new List <string>(); List <string> status = new List <string>(); if ((registers.Status & 0x01) == 0x01) { status.Add("ERR"); } if ((registers.Status & 0x02) == 0x02) { status.Add("IDX"); } if ((registers.Status & 0x04) == 0x04) { status.Add("CORR"); } if ((registers.Status & 0x08) == 0x08) { status.Add("DRQ"); } if ((registers.Status & 0x10) == 0x10) { status.Add("SRV"); } if ((registers.Status & 0x20) == 0x20) { status.Add("DF"); } if ((registers.Status & 0x40) == 0x40) { status.Add("RDY"); } if ((registers.Status & 0x80) == 0x80) { status.Add("BSY"); } if ((registers.Error & 0x01) == 0x01) { error.Add("AMNF"); } if ((registers.Error & 0x02) == 0x02) { error.Add("T0NF"); } if ((registers.Error & 0x04) == 0x04) { error.Add("ABRT"); } if ((registers.Error & 0x08) == 0x08) { error.Add("MCR"); } if ((registers.Error & 0x10) == 0x10) { error.Add("IDNF"); } if ((registers.Error & 0x20) == 0x20) { error.Add("MC"); } if ((registers.Error & 0x40) == 0x40) { error.Add("UNC"); } if ((registers.Error & 0x80) == 0x80) { error.Add("BBK"); } _logSw.WriteLine("ATA reading LBA {0} error: status = {1}, error = {2}.", block, string.Join(' ', status), string.Join(' ', error)); _logSw.Flush(); } }
/// <summary>Sends an ATA command in 28-bit LBA mode</summary> /// <returns>0 if no error occurred, otherwise, errno</returns> /// <param name="dev">CAM device</param> /// <param name="buffer">Buffer for SCSI command response</param> /// <param name="timeout">Timeout in seconds</param> /// <param name="duration">Time it took to execute the command in milliseconds</param> /// <param name="sense"><c>True</c> if ATA error returned non-OK status</param> /// <param name="registers">Registers to send to drive</param> /// <param name="errorRegisters">Registers returned by drive</param> /// <param name="protocol">ATA protocol to use</param> internal static int SendAtaCommand(IntPtr dev, AtaRegistersLba28 registers, out AtaErrorRegistersLba28 errorRegisters, AtaProtocol protocol, ref byte[] buffer, uint timeout, out double duration, out bool sense) { duration = 0; sense = false; errorRegisters = new AtaErrorRegistersLba28(); if (buffer == null) { return(-1); } IntPtr ccbPtr = cam_getccb(dev); var ataio = (CcbAtaio)Marshal.PtrToStructure(ccbPtr, typeof(CcbAtaio)); ataio.ccb_h.func_code = XptOpcode.XptAtaIo; ataio.ccb_h.flags = AtaProtocolToCamFlags(protocol); ataio.ccb_h.xflags = 0; ataio.ccb_h.retry_count = 1; ataio.ccb_h.cbfcnp = IntPtr.Zero; ataio.ccb_h.timeout = timeout; ataio.data_ptr = Marshal.AllocHGlobal(buffer.Length); ataio.dxfer_len = (uint)buffer.Length; ataio.ccb_h.flags |= CcbFlags.CamDevQfrzdis; ataio.cmd.flags = CamAtaIoFlags.NeedResult; switch (protocol) { case AtaProtocol.Dma: case AtaProtocol.DmaQueued: case AtaProtocol.UDmaIn: case AtaProtocol.UDmaOut: ataio.cmd.flags |= CamAtaIoFlags.Dma; break; case AtaProtocol.FpDma: ataio.cmd.flags |= CamAtaIoFlags.Fpdma; break; } ataio.cmd.command = registers.Command; ataio.cmd.lba_high = registers.LbaHigh; ataio.cmd.lba_mid = registers.LbaMid; ataio.cmd.device = (byte)(0x40 | registers.DeviceHead); ataio.cmd.features = registers.Feature; ataio.cmd.sector_count = registers.SectorCount; ataio.cmd.lba_low = registers.LbaLow; Marshal.Copy(buffer, 0, ataio.data_ptr, buffer.Length); Marshal.StructureToPtr(ataio, ccbPtr, false); DateTime start = DateTime.UtcNow; int error = cam_send_ccb(dev, ccbPtr); DateTime end = DateTime.UtcNow; if (error < 0) { error = Marshal.GetLastWin32Error(); } ataio = (CcbAtaio)Marshal.PtrToStructure(ccbPtr, typeof(CcbAtaio)); if ((ataio.ccb_h.status & CamStatus.CamStatusMask) != CamStatus.CamReqCmp && (ataio.ccb_h.status & CamStatus.CamStatusMask) != CamStatus.CamScsiStatusError) { error = Marshal.GetLastWin32Error(); AaruConsole.DebugWriteLine("FreeBSD devices", "CAM status {0} error {1}", ataio.ccb_h.status, error); sense = true; } if ((ataio.ccb_h.status & CamStatus.CamStatusMask) == CamStatus.CamAtaStatusError) { sense = true; } errorRegisters.LbaHigh = ataio.res.lba_high; errorRegisters.LbaMid = ataio.res.lba_mid; errorRegisters.DeviceHead = ataio.res.device; errorRegisters.Error = ataio.res.error; errorRegisters.LbaLow = ataio.res.lba_low; errorRegisters.SectorCount = ataio.res.sector_count; errorRegisters.Status = ataio.res.status; buffer = new byte[ataio.dxfer_len]; Marshal.Copy(ataio.data_ptr, buffer, 0, buffer.Length); duration = (end - start).TotalMilliseconds; Marshal.FreeHGlobal(ataio.data_ptr); cam_freeccb(ccbPtr); sense = errorRegisters.Error != 0 || (errorRegisters.Status & 0xA5) != 0 || error != 0; return(error); }
public int SendAtaCommand(AtaRegistersLba28 registers, out AtaErrorRegistersLba28 errorRegisters, AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer, uint timeout, bool transferBlocks, out double duration, out bool sense) { duration = 0; sense = true; errorRegisters = new AtaErrorRegistersLba28(); var cmdPkt = new AaruPacketCmdAtaLba28 { hdr = new AaruPacketHeader { remote_id = Consts.RemoteId, packet_id = Consts.PacketId, version = Consts.PacketVersion, packetType = AaruPacketType.CommandAtaLba28 }, registers = registers, protocol = (byte)protocol, transferRegister = (byte)transferRegister, transferBlocks = transferBlocks, timeout = timeout * 1000 }; if (buffer != null) { cmdPkt.buf_len = (uint)buffer.Length; } cmdPkt.hdr.len = (uint)(Marshal.SizeOf <AaruPacketCmdAtaLba28>() + cmdPkt.buf_len); byte[] pktBuf = Marshal.StructureToByteArrayLittleEndian(cmdPkt); byte[] buf = new byte[cmdPkt.hdr.len]; Array.Copy(pktBuf, 0, buf, 0, Marshal.SizeOf <AaruPacketCmdAtaLba28>()); if (buffer != null) { Array.Copy(buffer, 0, buf, Marshal.SizeOf <AaruPacketCmdAtaLba28>(), cmdPkt.buf_len); } int len = _socket.Send(buf, SocketFlags.None); if (len != buf.Length) { AaruConsole.ErrorWriteLine("Could not write to the network..."); return(-1); } byte[] hdrBuf = new byte[Marshal.SizeOf <AaruPacketHeader>()]; len = Receive(_socket, hdrBuf, hdrBuf.Length, SocketFlags.Peek); if (len < hdrBuf.Length) { AaruConsole.ErrorWriteLine("Could not read from the network..."); return(-1); } AaruPacketHeader hdr = Marshal.ByteArrayToStructureLittleEndian <AaruPacketHeader>(hdrBuf); if (hdr.remote_id != Consts.RemoteId || hdr.packet_id != Consts.PacketId) { AaruConsole.ErrorWriteLine("Received data is not an Aaru Remote Packet..."); return(-1); } if (hdr.packetType != AaruPacketType.ResponseAtaLba28) { AaruConsole.ErrorWriteLine("Expected ATA LBA28 Response Packet, got packet type {0}...", hdr.packetType); return(-1); } buf = new byte[hdr.len]; len = Receive(_socket, buf, buf.Length, SocketFlags.None); if (len < buf.Length) { AaruConsole.ErrorWriteLine("Could not read from the network..."); return(-1); } AaruPacketResAtaLba28 res = Marshal.ByteArrayToStructureLittleEndian <AaruPacketResAtaLba28>(buf); buffer = new byte[res.buf_len]; Array.Copy(buf, Marshal.SizeOf <AaruPacketResAtaLba28>(), buffer, 0, res.buf_len); duration = res.duration; sense = res.sense != 0; errorRegisters = res.registers; return((int)res.error_no); }
public bool ReadDma(out byte[] buffer, out AtaErrorRegistersLba28 statusRegisters, uint lba, byte count, uint timeout, out double duration) { return(ReadDma(out buffer, out statusRegisters, true, lba, count, timeout, out duration)); }
/// <summary>Sends an ATA command in 28-bit LBA mode</summary> /// <returns>0 if no error occurred, otherwise, errno</returns> /// <param name="fd">File handle</param> /// <param name="buffer">Buffer for SCSI command response</param> /// <param name="timeout">Timeout in seconds</param> /// <param name="duration">Time it took to execute the command in milliseconds</param> /// <param name="sense"><c>True</c> if ATA error returned non-OK status</param> /// <param name="registers">Registers to send to drive</param> /// <param name="errorRegisters">Registers returned by drive</param> /// <param name="protocol">ATA protocol to use</param> /// <param name="transferRegister">Which register contains the transfer count</param> /// <param name="transferBlocks">Set to <c>true</c> if the transfer count is in blocks, otherwise it is in bytes</param> internal static int SendAtaCommand(int fd, AtaRegistersLba28 registers, out AtaErrorRegistersLba28 errorRegisters, AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer, uint timeout, bool transferBlocks, out double duration, out bool sense) { duration = 0; sense = false; errorRegisters = new AtaErrorRegistersLba28(); if (buffer == null) { return(-1); } byte[] cdb = new byte[16]; cdb[0] = (byte)ScsiCommands.AtaPassThrough16; cdb[1] = (byte)(((byte)protocol << 1) & 0x1E); if (transferRegister != AtaTransferRegister.NoTransfer && protocol != AtaProtocol.NonData) { switch (protocol) { case AtaProtocol.PioIn: case AtaProtocol.UDmaIn: cdb[2] = 0x08; break; default: cdb[2] = 0x00; break; } if (transferBlocks) { cdb[2] |= 0x04; } cdb[2] |= (byte)((int)transferRegister & 0x03); } cdb[2] |= 0x20; cdb[4] = registers.Feature; cdb[6] = registers.SectorCount; cdb[8] = registers.LbaLow; cdb[10] = registers.LbaMid; cdb[12] = registers.LbaHigh; cdb[13] = registers.DeviceHead; cdb[14] = registers.Command; int error = SendScsiCommand(fd, cdb, ref buffer, out byte[] senseBuffer, timeout, AtaProtocolToScsiDirection(protocol), out duration, out sense); if (senseBuffer.Length < 22 || (senseBuffer[8] != 0x09 && senseBuffer[9] != 0x0C)) { return(error); } errorRegisters.Error = senseBuffer[11]; errorRegisters.SectorCount = senseBuffer[13]; errorRegisters.LbaLow = senseBuffer[15]; errorRegisters.LbaMid = senseBuffer[17]; errorRegisters.LbaHigh = senseBuffer[19]; errorRegisters.DeviceHead = senseBuffer[20]; errorRegisters.Status = senseBuffer[21]; sense = errorRegisters.Error != 0 || (errorRegisters.Status & 0xA5) != 0; return(error); }
public bool ReadLong(out byte[] buffer, out AtaErrorRegistersLba28 statusRegisters, uint lba, uint blockSize, uint timeout, out double duration) { return(ReadLong(out buffer, out statusRegisters, true, lba, blockSize, timeout, out duration)); }