Ejemplo n.º 1
0
        /// <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.");
            }
        }
Ejemplo n.º 2
0
 /// <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);
Ejemplo n.º 3
0
        /// <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));
        }
Ejemplo n.º 4
0
        /// <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));
        }
Ejemplo n.º 5
0
        /// <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.");
            }
        }
Ejemplo n.º 6
0
        /// <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);
        }
Ejemplo n.º 7
0
        /// <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);
        }
Ejemplo n.º 8
0
        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);
        }