/// <summary> /// Sends an ATA/ATAPI command to this device using CHS 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(AtaRegistersChs registers, out AtaErrorRegistersChs 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, AtaRegistersChs registers, out AtaErrorRegistersChs 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 CHS 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(AtaRegistersChs registers, out AtaErrorRegistersChs 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)); }
/// <summary> /// Sends an ATA command in CHS 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, AtaRegistersChs registers, out AtaErrorRegistersChs 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."); } }
/// <summary>Converts ATA protocol to SG_IO direction</summary> /// <param name="protocol">ATA protocol</param> /// <returns>SG_IO direction</returns> static ScsiIoctlDirection AtaProtocolToScsiDirection(AtaProtocol protocol) { switch (protocol) { case AtaProtocol.DeviceDiagnostic: case AtaProtocol.DeviceReset: case AtaProtocol.HardReset: case AtaProtocol.NonData: case AtaProtocol.SoftReset: case AtaProtocol.ReturnResponse: return(ScsiIoctlDirection.None); case AtaProtocol.PioIn: case AtaProtocol.UDmaIn: return(ScsiIoctlDirection.In); case AtaProtocol.PioOut: case AtaProtocol.UDmaOut: return(ScsiIoctlDirection.Out); default: return(ScsiIoctlDirection.Unspecified); } }
/// <summary>Converts ATA protocol to CAM flags</summary> /// <param name="protocol">ATA protocol</param> /// <returns>CAM flags</returns> static CcbFlags AtaProtocolToCamFlags(AtaProtocol protocol) { switch (protocol) { case AtaProtocol.DeviceDiagnostic: case AtaProtocol.DeviceReset: case AtaProtocol.HardReset: case AtaProtocol.NonData: case AtaProtocol.SoftReset: case AtaProtocol.ReturnResponse: return(CcbFlags.CamDirNone); case AtaProtocol.PioIn: case AtaProtocol.UDmaIn: return(CcbFlags.CamDirIn); case AtaProtocol.PioOut: case AtaProtocol.UDmaOut: return(CcbFlags.CamDirOut); default: return(CcbFlags.CamDirNone); } }
/// <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 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."); } }
/// <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>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); }
/// <summary> /// Sends an ATA command in CHS 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, AtaRegistersChs registers, out AtaErrorRegistersChs errorRegisters, AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer, uint timeout, bool transferBlocks, out double duration, out bool sense) { duration = 0; sense = false; errorRegisters = new AtaErrorRegistersChs(); 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.Sector; cdb[10] = registers.CylinderLow; cdb[12] = registers.CylinderHigh; 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.Sector = senseBuffer[15]; errorRegisters.CylinderLow = senseBuffer[17]; errorRegisters.CylinderHigh = senseBuffer[19]; errorRegisters.DeviceHead = senseBuffer[20]; errorRegisters.Status = senseBuffer[21]; sense = errorRegisters.Error != 0 || (errorRegisters.Status & 0xA5) != 0; return(error); }
/// <summary> /// Sends an ATA command in CHS 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, AtaRegistersChs registers, out AtaErrorRegistersChs errorRegisters, AtaProtocol protocol, ref byte[] buffer, uint timeout, out double duration, out bool sense) { duration = 0; sense = false; errorRegisters = new AtaErrorRegistersChs(); if (buffer == null) { return(-1); } IntPtr ccbPtr = cam_getccb(dev); CcbAtaio 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.CylinderHigh; ataio.cmd.lba_mid = registers.CylinderLow; ataio.cmd.device = (byte)(0x40 | registers.DeviceHead); ataio.cmd.features = registers.Feature; ataio.cmd.sector_count = registers.SectorCount; ataio.cmd.lba_low = registers.Sector; 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(); DicConsole.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.CylinderHigh = ataio.res.lba_high; errorRegisters.CylinderLow = ataio.res.lba_mid; errorRegisters.DeviceHead = ataio.res.device; errorRegisters.Error = ataio.res.error; errorRegisters.Sector = 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(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); }
/// <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); }