public bool GetNativeMaxAddressExt(out ulong lba, out AtaErrorRegistersLba48 statusRegisters, uint timeout, out double duration) { lba = 0; byte[] buffer = new byte[0]; AtaRegistersLba48 registers = new AtaRegistersLba48 { Command = (byte)AtaCommands.NativeMaxAddress, Feature = 0x0000 }; 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 = statusRegisters.LbaHigh; lba *= 0x100000000; lba += (ulong)(statusRegisters.LbaMid << 16); lba += statusRegisters.LbaLow; } DicConsole.DebugWriteLine("ATA Device", "GET NATIVE MAX ADDRESS EXT took {0} ms.", duration); return(sense); }
public bool ReadLog(out byte[] buffer, out AtaErrorRegistersLba48 statusRegisters, byte logAddress, ushort pageNumber, ushort count, uint timeout, out double duration) { buffer = new byte[512 * count]; AtaRegistersLba48 registers = new AtaRegistersLba48 { Command = (byte)AtaCommands.ReadLogExt, SectorCount = count, LbaLow = (ushort)((pageNumber & 0xFF) * 0x100), LbaHigh = (ushort)((pageNumber & 0xFF00) / 0x100) }; registers.LbaLow += logAddress; 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 LOG EXT took {0} ms.", duration); return(sense); }
/// <summary>Sends an ATA command in 48-bit 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, AtaRegistersLba48 registers, out AtaErrorRegistersLba48 errorRegisters, AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer, uint timeout, bool transferBlocks, out double duration, out bool sense) { switch (ptId) { case PlatformID.Win32NT: { // No check for Windows version. A 48-bit ATA disk simply does not work on earlier systems 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 Read(out byte[] buffer, out AtaErrorRegistersLba48 statusRegisters, ulong lba, ushort count, uint timeout, out double duration) { buffer = count == 0 ? new byte[512 * 65536] : new byte[512 * count]; AtaRegistersLba48 registers = new AtaRegistersLba48 { Command = (byte)AtaCommands.ReadExt, SectorCount = count, LbaHigh = (ushort)((lba & 0xFFFF00000000) / 0x100000000), LbaMid = (ushort)((lba & 0xFFFF0000) / 0x10000), LbaLow = (ushort)((lba & 0xFFFF) / 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 SECTORS EXT took {0} ms.", duration); return(sense); }
/// <summary> /// Sends an ATA/ATAPI command to this device using 48-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(AtaRegistersLba48 registers, out AtaErrorRegistersLba48 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 48-bit LBA 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, AtaRegistersLba48 registers, out AtaErrorRegistersLba48 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 48-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(AtaRegistersLba48 registers, out AtaErrorRegistersLba48 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 static string DecodeAtaRegisters(AtaErrorRegistersLba48 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}", (ulong)(registers.DeviceHead & 0xF) * 0x100000000000 + registers.LbaHigh * (ulong)0x100000000L + (ulong)(registers.LbaMid << 16) + 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 48-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, AtaRegistersLba48 registers, out AtaErrorRegistersLba48 errorRegisters, AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer, uint timeout, bool transferBlocks, out double duration, out bool sense) { duration = 0; sense = false; errorRegisters = new AtaErrorRegistersLba48(); if (buffer == null) { return(-1); } byte[] cdb = new byte[16]; cdb[0] = (byte)ScsiCommands.AtaPassThrough16; cdb[1] = (byte)(((byte)protocol << 1) & 0x1E); cdb[1] |= 0x01; 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[3] = (byte)((registers.Feature & 0xFF00) >> 8); cdb[4] = (byte)(registers.Feature & 0xFF); cdb[5] = (byte)((registers.SectorCount & 0xFF00) >> 8); cdb[6] = (byte)(registers.SectorCount & 0xFF); cdb[7] = (byte)((registers.LbaLow & 0xFF00) >> 8); cdb[8] = (byte)(registers.LbaLow & 0xFF); cdb[9] = (byte)((registers.LbaMid & 0xFF00) >> 8); cdb[10] = (byte)(registers.LbaMid & 0xFF); cdb[11] = (byte)((registers.LbaHigh & 0xFF00) >> 8); cdb[12] = (byte)(registers.LbaHigh & 0xFF); 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 = (ushort)((senseBuffer[12] << 8) + senseBuffer[13]); errorRegisters.LbaLow = (ushort)((senseBuffer[14] << 8) + senseBuffer[15]); errorRegisters.LbaMid = (ushort)((senseBuffer[16] << 8) + senseBuffer[17]); errorRegisters.LbaHigh = (ushort)((senseBuffer[18] << 8) + senseBuffer[19]); errorRegisters.DeviceHead = senseBuffer[20]; errorRegisters.Status = senseBuffer[21]; sense = errorRegisters.Error != 0 || (errorRegisters.Status & 0xA5) != 0; sense |= error != 0; return(error); }
/// <summary> /// Sends an ATA command in 48-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, AtaRegistersLba48 registers, out AtaErrorRegistersLba48 errorRegisters, AtaProtocol protocol, ref byte[] buffer, uint timeout, out double duration, out bool sense) { duration = 0; sense = false; errorRegisters = new AtaErrorRegistersLba48(); 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 { CylinderHigh = (byte)((registers.LbaHigh & 0xFF00) >> 8), CylinderLow = (byte)((registers.LbaMid & 0xFF00) >> 8), Features = (byte)((registers.Feature & 0xFF00) >> 8), SectorCount = (byte)((registers.SectorCount & 0xFF00) >> 8), SectorNumber = (byte)((registers.LbaLow & 0xFF00) >> 8) }, CurrentTaskFile = new AtaTaskFile { Command = registers.Command, CylinderHigh = (byte)(registers.LbaHigh & 0xFF), CylinderLow = (byte)(registers.LbaMid & 0xFF), DeviceHead = registers.DeviceHead, Features = (byte)(registers.Feature & 0xFF), SectorCount = (byte)(registers.SectorCount & 0xFF), SectorNumber = (byte)(registers.LbaLow & 0xFF) } }, 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.SectorCount = (ushort)((aptdBuf.aptd.PreviousTaskFile.SectorCount << 8) + aptdBuf.aptd.CurrentTaskFile.SectorCount); errorRegisters.LbaLow = (ushort)((aptdBuf.aptd.PreviousTaskFile.SectorNumber << 8) + aptdBuf.aptd.CurrentTaskFile.SectorNumber); errorRegisters.LbaMid = (ushort)((aptdBuf.aptd.PreviousTaskFile.CylinderLow << 8) + aptdBuf.aptd.CurrentTaskFile.CylinderLow); errorRegisters.LbaHigh = (ushort)((aptdBuf.aptd.PreviousTaskFile.CylinderHigh << 8) + aptdBuf.aptd.CurrentTaskFile.CylinderHigh); errorRegisters.DeviceHead = aptdBuf.aptd.CurrentTaskFile.DeviceHead; errorRegisters.Error = aptdBuf.aptd.CurrentTaskFile.Error; 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 48-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, AtaErrorRegistersLba48 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 48-bit 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, AtaRegistersLba48 registers, out AtaErrorRegistersLba48 errorRegisters, AtaProtocol protocol, ref byte[] buffer, uint timeout, out double duration, out bool sense) { duration = 0; sense = false; errorRegisters = new AtaErrorRegistersLba48(); // 48-bit ATA CAM commands can crash FreeBSD < 9.2-RELEASE if ((Environment.Version.Major == 9 && Environment.Version.Minor < 2) || Environment.Version.Major < 9) { return(-1); } 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 | CamAtaIoFlags.ExtendedCommand; 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.lba_high_exp = (byte)((registers.LbaHigh & 0xFF00) >> 8); ataio.cmd.lba_mid_exp = (byte)((registers.LbaMid & 0xFF00) >> 8); ataio.cmd.features_exp = (byte)((registers.Feature & 0xFF00) >> 8); ataio.cmd.sector_count_exp = (byte)((registers.SectorCount & 0xFF00) >> 8); ataio.cmd.lba_low_exp = (byte)((registers.LbaLow & 0xFF00) >> 8); ataio.cmd.lba_high = (byte)(registers.LbaHigh & 0xFF); ataio.cmd.lba_mid = (byte)(registers.LbaMid & 0xFF); ataio.cmd.features = (byte)(registers.Feature & 0xFF); ataio.cmd.sector_count = (byte)(registers.SectorCount & 0xFF); ataio.cmd.lba_low = (byte)(registers.LbaLow & 0xFF); ataio.cmd.command = registers.Command; ataio.cmd.device = (byte)(0x40 | registers.DeviceHead); 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.SectorCount = (ushort)((ataio.res.sector_count_exp << 8) + ataio.res.sector_count); errorRegisters.LbaLow = (ushort)((ataio.res.lba_low_exp << 8) + ataio.res.lba_low); errorRegisters.LbaMid = (ushort)((ataio.res.lba_mid_exp << 8) + ataio.res.lba_mid); errorRegisters.LbaHigh = (ushort)((ataio.res.lba_high_exp << 8) + ataio.res.lba_high); errorRegisters.DeviceHead = ataio.res.device; errorRegisters.Error = ataio.res.error; 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(AtaRegistersLba48 registers, out AtaErrorRegistersLba48 errorRegisters, AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer, uint timeout, bool transferBlocks, out double duration, out bool sense) { duration = 0; sense = true; errorRegisters = new AtaErrorRegistersLba48(); var cmdPkt = new AaruPacketCmdAtaLba48 { hdr = new AaruPacketHeader { remote_id = Consts.RemoteId, packet_id = Consts.PacketId, version = Consts.PacketVersion, packetType = AaruPacketType.CommandAtaLba48 }, 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 <AaruPacketCmdAtaLba48>() + cmdPkt.buf_len); byte[] pktBuf = Marshal.StructureToByteArrayLittleEndian(cmdPkt); byte[] buf = new byte[cmdPkt.hdr.len]; Array.Copy(pktBuf, 0, buf, 0, Marshal.SizeOf <AaruPacketCmdAtaLba48>()); if (buffer != null) { Array.Copy(buffer, 0, buf, Marshal.SizeOf <AaruPacketCmdAtaLba48>(), 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.ResponseAtaLba48) { AaruConsole.ErrorWriteLine("Expected ATA LBA48 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); } AaruPacketResAtaLba48 res = Marshal.ByteArrayToStructureLittleEndian <AaruPacketResAtaLba48>(buf); buffer = new byte[res.buf_len]; Array.Copy(buf, Marshal.SizeOf <AaruPacketResAtaLba48>(), buffer, 0, res.buf_len); duration = res.duration; sense = res.sense != 0; errorRegisters = res.registers; return((int)res.error_no); }