Renamed project files and folders

This commit is contained in:
2020-02-26 19:10:46 +00:00
parent e133798583
commit f5b199e483
1417 changed files with 109 additions and 109 deletions

View File

@@ -0,0 +1,597 @@
// /***************************************************************************
// The Disc Image Chef
// ----------------------------------------------------------------------------
//
// Filename : Command.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// Component : FreeBSD direct device access.
//
// --[ Description ] ----------------------------------------------------------
//
// Contains a high level representation of the FreeBSD syscalls used to
// directly interface devices.
//
// --[ License ] --------------------------------------------------------------
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 2.1 of the
// License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2020 Natalia Portillo
// ****************************************************************************/
using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using DiscImageChef.Console;
using DiscImageChef.Decoders.ATA;
using static DiscImageChef.Devices.FreeBSD.Extern;
namespace DiscImageChef.Devices.FreeBSD
{
[SuppressMessage("ReSharper", "BitwiseOperatorOnEnumWithoutFlags")]
static class Command
{
const int CAM_MAX_CDBLEN = 16;
/// <summary>
/// Sends a SCSI command (64-bit arch)
/// </summary>
/// <returns>0 if no error occurred, otherwise, errno</returns>
/// <param name="dev">CAM device</param>
/// <param name="cdb">SCSI CDB</param>
/// <param name="buffer">Buffer for SCSI command response</param>
/// <param name="senseBuffer">Buffer with the SCSI sense</param>
/// <param name="timeout">Timeout in seconds</param>
/// <param name="direction">SCSI command transfer direction</param>
/// <param name="duration">Time it took to execute the command in milliseconds</param>
/// <param name="sense">
/// <c>True</c> if SCSI error returned non-OK status and <paramref name="senseBuffer" /> contains SCSI
/// sense
/// </param>
internal static int SendScsiCommand64(IntPtr dev, byte[] cdb, ref byte[] buffer,
out byte[] senseBuffer,
uint timeout, CcbFlags direction, out double duration, out bool sense)
{
senseBuffer = null;
duration = 0;
sense = false;
if(buffer == null) return -1;
IntPtr ccbPtr = cam_getccb(dev);
IntPtr cdbPtr = IntPtr.Zero;
if(ccbPtr.ToInt64() == 0)
{
sense = true;
return Marshal.GetLastWin32Error();
}
CcbScsiio64 csio = (CcbScsiio64)Marshal.PtrToStructure(ccbPtr, typeof(CcbScsiio64));
csio.ccb_h.func_code = XptOpcode.XptScsiIo;
csio.ccb_h.flags = direction;
csio.ccb_h.xflags = 0;
csio.ccb_h.retry_count = 1;
csio.ccb_h.cbfcnp = IntPtr.Zero;
csio.ccb_h.timeout = timeout;
csio.data_ptr = Marshal.AllocHGlobal(buffer.Length);
csio.dxfer_len = (uint)buffer.Length;
csio.sense_len = 32;
csio.cdb_len = (byte)cdb.Length;
// TODO: Create enum?
csio.tag_action = 0x20;
csio.cdb_bytes = new byte[CAM_MAX_CDBLEN];
if(cdb.Length <= CAM_MAX_CDBLEN) Array.Copy(cdb, 0, csio.cdb_bytes, 0, cdb.Length);
else
{
cdbPtr = Marshal.AllocHGlobal(cdb.Length);
byte[] cdbPtrBytes = BitConverter.GetBytes(cdbPtr.ToInt64());
Array.Copy(cdbPtrBytes, 0, csio.cdb_bytes, 0, IntPtr.Size);
csio.ccb_h.flags |= CcbFlags.CamCdbPointer;
}
csio.ccb_h.flags |= CcbFlags.CamDevQfrzdis;
Marshal.Copy(buffer, 0, csio.data_ptr, buffer.Length);
Marshal.StructureToPtr(csio, ccbPtr, false);
DateTime start = DateTime.UtcNow;
int error = cam_send_ccb(dev, ccbPtr);
DateTime end = DateTime.UtcNow;
if(error < 0) error = Marshal.GetLastWin32Error();
csio = (CcbScsiio64)Marshal.PtrToStructure(ccbPtr, typeof(CcbScsiio64));
if((csio.ccb_h.status & CamStatus.CamStatusMask) != CamStatus.CamReqCmp &&
(csio.ccb_h.status & CamStatus.CamStatusMask) != CamStatus.CamScsiStatusError)
{
error = Marshal.GetLastWin32Error();
DicConsole.DebugWriteLine("FreeBSD devices", "CAM status {0} error {1}", csio.ccb_h.status, error);
sense = true;
}
if((csio.ccb_h.status & CamStatus.CamStatusMask) == CamStatus.CamScsiStatusError)
{
sense = true;
senseBuffer = new byte[1];
senseBuffer[0] = csio.scsi_status;
}
if((csio.ccb_h.status & CamStatus.CamAutosnsValid) != 0)
if(csio.sense_len - csio.sense_resid > 0)
{
sense = (csio.ccb_h.status & CamStatus.CamStatusMask) == CamStatus.CamScsiStatusError;
senseBuffer = new byte[csio.sense_len - csio.sense_resid];
senseBuffer[0] = csio.sense_data.error_code;
Array.Copy(csio.sense_data.sense_buf, 0, senseBuffer, 1, senseBuffer.Length - 1);
}
buffer = new byte[csio.dxfer_len];
cdb = new byte[csio.cdb_len];
Marshal.Copy(csio.data_ptr, buffer, 0, buffer.Length);
if(csio.ccb_h.flags.HasFlag(CcbFlags.CamCdbPointer))
Marshal.Copy(new IntPtr(BitConverter.ToInt64(csio.cdb_bytes, 0)), cdb, 0, cdb.Length);
else Array.Copy(csio.cdb_bytes, 0, cdb, 0, cdb.Length);
duration = (end - start).TotalMilliseconds;
if(csio.ccb_h.flags.HasFlag(CcbFlags.CamCdbPointer)) Marshal.FreeHGlobal(cdbPtr);
Marshal.FreeHGlobal(csio.data_ptr);
cam_freeccb(ccbPtr);
return error;
}
/// <summary>
/// Sends a SCSI command (32-bit arch)
/// </summary>
/// <returns>0 if no error occurred, otherwise, errno</returns>
/// <param name="dev">CAM device</param>
/// <param name="cdb">SCSI CDB</param>
/// <param name="buffer">Buffer for SCSI command response</param>
/// <param name="senseBuffer">Buffer with the SCSI sense</param>
/// <param name="timeout">Timeout in seconds</param>
/// <param name="direction">SCSI command transfer direction</param>
/// <param name="duration">Time it took to execute the command in milliseconds</param>
/// <param name="sense">
/// <c>True</c> if SCSI error returned non-OK status and <paramref name="senseBuffer" /> contains SCSI
/// sense
/// </param>
internal static int SendScsiCommand(IntPtr dev, byte[] cdb, ref byte[] buffer,
out byte[] senseBuffer,
uint timeout, CcbFlags direction, out double duration, out bool sense)
{
senseBuffer = null;
duration = 0;
sense = false;
if(buffer == null) return -1;
IntPtr ccbPtr = cam_getccb(dev);
IntPtr cdbPtr = IntPtr.Zero;
if(ccbPtr.ToInt32() == 0)
{
sense = true;
return Marshal.GetLastWin32Error();
}
CcbScsiio csio = (CcbScsiio)Marshal.PtrToStructure(ccbPtr, typeof(CcbScsiio));
csio.ccb_h.func_code = XptOpcode.XptScsiIo;
csio.ccb_h.flags = direction;
csio.ccb_h.xflags = 0;
csio.ccb_h.retry_count = 1;
csio.ccb_h.cbfcnp = IntPtr.Zero;
csio.ccb_h.timeout = timeout;
csio.data_ptr = Marshal.AllocHGlobal(buffer.Length);
csio.dxfer_len = (uint)buffer.Length;
csio.sense_len = 32;
csio.cdb_len = (byte)cdb.Length;
// TODO: Create enum?
csio.tag_action = 0x20;
csio.cdb_bytes = new byte[CAM_MAX_CDBLEN];
if(cdb.Length <= CAM_MAX_CDBLEN) Array.Copy(cdb, 0, csio.cdb_bytes, 0, cdb.Length);
else
{
cdbPtr = Marshal.AllocHGlobal(cdb.Length);
byte[] cdbPtrBytes = BitConverter.GetBytes(cdbPtr.ToInt32());
Array.Copy(cdbPtrBytes, 0, csio.cdb_bytes, 0, IntPtr.Size);
csio.ccb_h.flags |= CcbFlags.CamCdbPointer;
}
csio.ccb_h.flags |= CcbFlags.CamDevQfrzdis;
Marshal.Copy(buffer, 0, csio.data_ptr, buffer.Length);
Marshal.StructureToPtr(csio, ccbPtr, false);
DateTime start = DateTime.UtcNow;
int error = cam_send_ccb(dev, ccbPtr);
DateTime end = DateTime.UtcNow;
if(error < 0) error = Marshal.GetLastWin32Error();
csio = (CcbScsiio)Marshal.PtrToStructure(ccbPtr, typeof(CcbScsiio));
if((csio.ccb_h.status & CamStatus.CamStatusMask) != CamStatus.CamReqCmp &&
(csio.ccb_h.status & CamStatus.CamStatusMask) != CamStatus.CamScsiStatusError)
{
error = Marshal.GetLastWin32Error();
DicConsole.DebugWriteLine("FreeBSD devices", "CAM status {0} error {1}", csio.ccb_h.status, error);
sense = true;
}
if((csio.ccb_h.status & CamStatus.CamStatusMask) == CamStatus.CamScsiStatusError)
{
sense = true;
senseBuffer = new byte[1];
senseBuffer[0] = csio.scsi_status;
}
if((csio.ccb_h.status & CamStatus.CamAutosnsValid) != 0)
if(csio.sense_len - csio.sense_resid > 0)
{
sense = (csio.ccb_h.status & CamStatus.CamStatusMask) == CamStatus.CamScsiStatusError;
senseBuffer = new byte[csio.sense_len - csio.sense_resid];
senseBuffer[0] = csio.sense_data.error_code;
Array.Copy(csio.sense_data.sense_buf, 0, senseBuffer, 1, senseBuffer.Length - 1);
}
buffer = new byte[csio.dxfer_len];
cdb = new byte[csio.cdb_len];
Marshal.Copy(csio.data_ptr, buffer, 0, buffer.Length);
if(csio.ccb_h.flags.HasFlag(CcbFlags.CamCdbPointer))
Marshal.Copy(new IntPtr(BitConverter.ToInt32(csio.cdb_bytes, 0)), cdb, 0, cdb.Length);
else Array.Copy(csio.cdb_bytes, 0, cdb, 0, cdb.Length);
duration = (end - start).TotalMilliseconds;
if(csio.ccb_h.flags.HasFlag(CcbFlags.CamCdbPointer)) Marshal.FreeHGlobal(cdbPtr);
Marshal.FreeHGlobal(csio.data_ptr);
cam_freeccb(ccbPtr);
return error;
}
/// <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 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;
}
/// <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);
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.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();
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.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;
}
/// <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);
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 | 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();
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.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;
}
}
}

View File

@@ -0,0 +1,736 @@
// /***************************************************************************
// The Disc Image Chef
// ----------------------------------------------------------------------------
//
// Filename : Enums.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// Component : FreeBSD direct device access.
//
// --[ Description ] ----------------------------------------------------------
//
// Contains enumerations necessary for directly interfacing devices under
// FreeBSD.
//
// --[ License ] --------------------------------------------------------------
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 2.1 of the
// License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2020 Natalia Portillo
// ****************************************************************************/
using System;
namespace DiscImageChef.Devices.FreeBSD
{
[Flags]
enum FileFlags
{
/// <summary>
/// O_RDONLY
/// </summary>
ReadOnly = 0x00000000,
/// <summary>
/// O_WRONLY
/// </summary>
WriteOnly = 0x00000001,
/// <summary>
/// O_RDWR
/// </summary>
ReadWrite = 0x00000002,
/// <summary>
/// O_NONBLOCK
/// </summary>
NonBlocking = 0x00000004,
/// <summary>
/// O_APPEND
/// </summary>
Append = 0x00000008,
/// <summary>
/// O_SHLOCK
/// </summary>
SharedLock = 0x00000010,
/// <summary>
/// O_EXLOCK
/// </summary>
ExclusiveLock = 0x00000020,
/// <summary>
/// O_ASYNC
/// </summary>
Async = 0x00000040,
/// <summary>
/// O_FSYNC
/// </summary>
SyncWrites = 0x00000080,
/// <summary>
/// O_NOFOLLOW
/// </summary>
NoFollowSymlink = 0x00000100,
/// <summary>
/// O_CREAT
/// </summary>
OpenOrCreate = 0x00000200,
/// <summary>
/// O_TRUNC
/// </summary>
Truncate = 0x00000400,
/// <summary>
/// O_EXCL
/// </summary>
CreateNew = 0x00000800,
/// <summary>
/// O_NOCTTY
/// </summary>
NoControlTty = 0x00008000,
/// <summary>
/// O_DIRECT
/// </summary>
Direct = 0x00010000,
/// <summary>
/// O_DIRECTORY
/// </summary>
Directory = 0x00020000,
/// <summary>
/// O_EXEC
/// </summary>
Execute = 0x00040000,
/// <summary>
/// O_TTY_INIT
/// </summary>
InitializeTty = 0x00080000,
/// <summary>
/// O_CLOEXEC
/// </summary>
CloseOnExec = 0x00100000
}
[Flags]
enum CamAtaIoFlags : byte
{
/// <summary>
/// 48-bit command
/// </summary>
ExtendedCommand = 0x01,
/// <summary>
/// FPDMA command
/// </summary>
Fpdma = 0x02,
/// <summary>
/// Control, not a command
/// </summary>
Control = 0x04,
/// <summary>
/// Needs result
/// </summary>
NeedResult = 0x08,
/// <summary>
/// DMA command
/// </summary>
Dma = 0x10
}
/// <summary>XPT Opcodes for xpt_action</summary>
[Flags]
enum XptOpcode
{
// Function code flags are bits greater than 0xff
/// <summary>Non-immediate function code</summary>
XptFcQueued = 0x100,
XptFcUserCcb = 0x200,
/// <summary>Only for the transport layer device</summary>
XptFcXptOnly = 0x400,
/// <summary>Passes through the device queues</summary>
XptFcDevQueued = 0x800 | XptFcQueued,
// Common function commands: 0x00->0x0F
/// <summary>Execute Nothing</summary>
XptNoop = 0x00,
/// <summary>Execute the requested I/O operation</summary>
XptScsiIo = 0x01 | XptFcDevQueued,
/// <summary>Get type information for specified device</summary>
XptGdevType = 0x02,
/// <summary>Get a list of peripheral devices</summary>
XptGdevlist = 0x03,
/// <summary>Path routing inquiry</summary>
XptPathInq = 0x04,
/// <summary>Release a frozen device queue</summary>
XptRelSimq = 0x05,
/// <summary>Set Asynchronous Callback Parameters</summary>
XptSasyncCb = 0x06,
/// <summary>Set device type information</summary>
XptSdevType = 0x07,
/// <summary>(Re)Scan the SCSI Bus</summary>
XptScanBus = 0x08 | XptFcQueued | XptFcUserCcb | XptFcXptOnly,
/// <summary>Get EDT entries matching the given pattern</summary>
XptDevMatch = 0x09 | XptFcXptOnly,
/// <summary>Turn on debugging for a bus, target or lun</summary>
XptDebug = 0x0a,
/// <summary>Path statistics (error counts, etc.)</summary>
XptPathStats = 0x0b,
/// <summary>Device statistics (error counts, etc.)</summary>
XptGdevStats = 0x0c,
/// <summary>Get/Set Device advanced information</summary>
XptDevAdvinfo = 0x0e,
/// <summary>Asynchronous event</summary>
XptAsync = 0x0f | XptFcQueued | XptFcUserCcb | XptFcXptOnly,
/// <summary>SCSI Control Functions: 0x10->0x1F</summary>
/// <summary>Abort the specified CCB</summary>
XptAbort = 0x10,
/// <summary>Reset the specified SCSI bus</summary>
XptResetBus = 0x11 | XptFcXptOnly,
/// <summary>Bus Device Reset the specified SCSI device</summary>
XptResetDev = 0x12 | XptFcDevQueued,
/// <summary>Terminate the I/O process</summary>
XptTermIo = 0x13,
/// <summary>Scan Logical Unit</summary>
XptScanLun = 0x14 | XptFcQueued | XptFcUserCcb | XptFcXptOnly,
/// <summary>Get default/user transfer settings for the target</summary>
XptGetTranSettings = 0x15,
/// <summary>Set transfer rate/width negotiation settings</summary>
XptSetTranSettings = 0x16,
/// <summary>Calculate the geometry parameters for a device give the sector size and volume size.</summary>
XptCalcGeometry = 0x17,
/// <summary>Execute the requested ATA I/O operation</summary>
XptAtaIo = 0x18 | XptFcDevQueued,
/// <summary>Compat only</summary>
XptGetSimKnobOld = 0x18,
/// <summary>Set SIM specific knob values.</summary>
XptSetSimKnob = 0x19,
/// <summary>Get SIM specific knob values.</summary>
XptGetSimKnob = 0x1a,
/// <summary>Serial Management Protocol</summary>
XptSmpIo = 0x1b | XptFcDevQueued,
/// <summary>Scan Target</summary>
XptScanTgt = 0x1E | XptFcQueued | XptFcUserCcb | XptFcXptOnly,
// HBA engine commands 0x20->0x2F
/// <summary>HBA engine feature inquiry</summary>
XptEngInq = 0x20 | XptFcXptOnly,
/// <summary>HBA execute engine request</summary>
XptEngExec = 0x21 | XptFcDevQueued,
// Target mode commands: 0x30->0x3F
/// <summary>Enable LUN as a target</summary>
XptEnLun = 0x30,
/// <summary>Execute target I/O request</summary>
XptTargetIo = 0x31 | XptFcDevQueued,
/// <summary>Accept Host Target Mode CDB</summary>
XptAcceptTargetIo = 0x32 | XptFcQueued | XptFcUserCcb,
/// <summary>Continue Host Target I/O Connection</summary>
XptContTargetIo = 0x33 | XptFcDevQueued,
/// <summary>Notify Host Target driver of event (obsolete)</summary>
XptImmedNotify = 0x34 | XptFcQueued | XptFcUserCcb,
/// <summary>Acknowledgement of event (obsolete)</summary>
XptNotifyAck = 0x35,
/// <summary>Notify Host Target driver of event</summary>
XptImmediateNotify = 0x36 | XptFcQueued | XptFcUserCcb,
/// <summary>Acknowledgement of event</summary>
XptNotifyAcknowledge = 0x37 | XptFcQueued | XptFcUserCcb,
/// <summary>Vendor Unique codes: 0x80->0x8F</summary>
XptVunique = 0x80
}
enum CcbDevMatchStatus
{
CamDevMatchLast,
CamDevMatchMore,
CamDevMatchListChanged,
CamDevMatchSizeError,
CamDevMatchError
}
enum DevMatchType
{
DevMatchPeriph = 0,
DevMatchDevice,
DevMatchBus
}
[Flags]
enum PeriphPatternFlags
{
PeriphMatchNone = 0x000,
PeriphMatchPath = 0x001,
PeriphMatchTarget = 0x002,
PeriphMatchLun = 0x004,
PeriphMatchName = 0x008,
PeriphMatchUnit = 0x010
// PERIPH_MATCH_ANY = 0x01f
}
[Flags]
enum DevPatternFlags
{
DevMatchNone = 0x000,
DevMatchPath = 0x001,
DevMatchTarget = 0x002,
DevMatchLun = 0x004,
DevMatchInquiry = 0x008,
DevMatchDevid = 0x010
// DEV_MATCH_ANY = 0x00f
}
[Flags]
enum BusPatternFlags
{
BusMatchNone = 0x000,
BusMatchPath = 0x001,
BusMatchName = 0x002,
BusMatchUnit = 0x004,
BusMatchBusId = 0x008
// BUS_MATCH_ANY = 0x00f
}
[Flags]
enum DevResultFlags
{
DevResultNoflag = 0x00,
DevResultUnconfigured = 0x01
}
enum CamProto
{
ProtoUnknown,
ProtoUnspecified,
/// <summary>
/// Small Computer System Interface
/// </summary>
ProtoScsi,
/// <summary>
/// AT Attachment
/// </summary>
ProtoAta,
/// <summary>
/// AT Attachment Packetized Interface
/// </summary>
ProtoAtapi,
/// <summary>
/// SATA Port Multiplier
/// </summary>
ProtoSatapm,
/// <summary>
/// SATA Enclosure Management Bridge
/// </summary>
ProtoSemb,
/// <summary>
/// NVMe
/// </summary>
ProtoNvme,
/// <summary>
/// MMC, SD, SDIO
/// </summary>
ProtoMmcsd
}
[Flags]
enum MmcCardFeatures
{
CardFeatureMemory = 0x1,
CardFeatureSdhc = 0x1 << 1,
CardFeatureSdio = 0x1 << 2,
CardFeatureSd20 = 0x1 << 3,
CardFeatureMmc = 0x1 << 4,
CardFeature18V = 0x1 << 5
}
enum CamGenerations : uint
{
CamBusGeneration = 0x00,
CamTargetGeneration = 0x01,
CamDevGeneration = 0x02,
CamPeriphGeneration = 0x03
}
[Flags]
enum DevPosType
{
CamDevPosNone = 0x000,
CamDevPosBus = 0x001,
CamDevPosTarget = 0x002,
CamDevPosDevice = 0x004,
CamDevPosPeriph = 0x008,
CamDevPosPdptr = 0x010,
// CAM_DEV_POS_TYPEMASK = 0xf00,
CamDevPosEdt = 0x100,
CamDevPosPdrv = 0x200
}
enum FreebsdIoctl : uint
{
Camiocommand = 0xC4D81802
}
[Flags]
enum CcbFlags : uint
{
/// <summary>
/// The CDB field is a pointer
/// </summary>
CamCdbPointer = 0x00000001,
/// <summary>
/// SIM queue actions are enabled
/// </summary>
CamQueueEnable = 0x00000002,
/// <summary>
/// CCB contains a linked CDB
/// </summary>
CamCdbLinked = 0x00000004,
/// <summary>
/// Perform transport negotiation with this command.
/// </summary>
CamNegotiate = 0x00000008,
/// <summary>
/// Data type with physical addrs
/// </summary>
CamDataIsphys = 0x00000010,
/// <summary>
/// Disable autosense feature
/// </summary>
CamDisAutosense = 0x00000020,
/// <summary>
/// Data direction (00:IN/OUT)
/// </summary>
CamDirBoth = 0x00000000,
/// <summary>
/// Data direction (01:DATA IN)
/// </summary>
CamDirIn = 0x00000040,
/// <summary>
/// Data direction (10:DATA OUT)
/// </summary>
CamDirOut = 0x00000080,
/// <summary>
/// Data direction (11:no data)
/// </summary>
CamDirNone = 0x000000C0,
/// <summary>
/// Data type (000:Virtual)
/// </summary>
CamDataVaddr = 0x00000000,
/// <summary>
/// Data type (001:Physical)
/// </summary>
CamDataPaddr = 0x00000010,
/// <summary>
/// Data type (010:sglist)
/// </summary>
CamDataSg = 0x00040000,
/// <summary>
/// Data type (011:sglist phys)
/// </summary>
CamDataSgPaddr = 0x00040010,
/// <summary>
/// Data type (100:bio)
/// </summary>
CamDataBio = 0x00200000,
/// <summary>
/// Use Soft reset alternative
/// </summary>
CamSoftRstOp = 0x00000100,
/// <summary>
/// Flush resid bytes on complete
/// </summary>
CamEngSync = 0x00000200,
/// <summary>
/// Disable DEV Q freezing
/// </summary>
CamDevQfrzdis = 0x00000400,
/// <summary>
/// Freeze DEV Q on execution
/// </summary>
CamDevQfreeze = 0x00000800,
/// <summary>
/// Command takes a lot of power
/// </summary>
CamHighPower = 0x00001000,
/// <summary>
/// Sense data is a pointer
/// </summary>
CamSensePtr = 0x00002000,
/// <summary>
/// Sense pointer is physical addr
/// </summary>
CamSensePhys = 0x00004000,
/// <summary>
/// Use the tag action in this ccb
/// </summary>
CamTagActionValid = 0x00008000,
/// <summary>
/// Pass driver does err. recovery
/// </summary>
CamPassErrRecover = 0x00010000,
/// <summary>
/// Disable disconnect
/// </summary>
CamDisDisconnect = 0x00020000,
/// <summary>
/// Message buffer ptr is physical
/// </summary>
CamMsgBufPhys = 0x00080000,
/// <summary>
/// Autosense data ptr is physical
/// </summary>
CamSnsBufPhys = 0x00100000,
/// <summary>
/// CDB poiner is physical
/// </summary>
CamCdbPhys = 0x00400000,
/// <summary>
/// SG list is for the HBA engine
/// </summary>
CamEngSglist = 0x00800000,
/* Phase cognizant mode flags */
/// <summary>
/// Disable autosave/restore ptrs
/// </summary>
CamDisAutosrp = 0x01000000,
/// <summary>
/// Disable auto disconnect
/// </summary>
CamDisAutodisc = 0x02000000,
/// <summary>
/// Target CCB available
/// </summary>
CamTgtCcbAvail = 0x04000000,
/// <summary>
/// The SIM runs in phase mode
/// </summary>
CamTgtPhaseMode = 0x08000000,
/// <summary>
/// Message buffer valid
/// </summary>
CamMsgbValid = 0x10000000,
/// <summary>
/// Status buffer valid
/// </summary>
CamStatusValid = 0x20000000,
/// <summary>
/// Data buffer valid
/// </summary>
CamDatabValid = 0x40000000,
/* Host target Mode flags */
/// <summary>
/// Send sense data with status
/// </summary>
CamSendSense = 0x08000000,
/// <summary>
/// Terminate I/O Message sup.
/// </summary>
CamTermIo = 0x10000000,
/// <summary>
/// Disconnects are mandatory
/// </summary>
CamDisconnect = 0x20000000,
/// <summary>
/// Send status after data phase
/// </summary>
CamSendStatus = 0x40000000,
/// <summary>
/// Call callback without lock.
/// </summary>
CamUnlocked = 0x80000000
}
enum CamStatus : uint
{
/// <summary>CCB request is in progress</summary>
CamReqInprog = 0x00,
/// <summary>CCB request completed without error</summary>
CamReqCmp = 0x01,
/// <summary>CCB request aborted by the host</summary>
CamReqAborted = 0x02,
/// <summary>Unable to abort CCB request</summary>
CamUaAbort = 0x03,
/// <summary>CCB request completed with an error</summary>
CamReqCmpErr = 0x04,
/// <summary>CAM subsystem is busy</summary>
CamBusy = 0x05,
/// <summary>CCB request was invalid</summary>
CamReqInvalid = 0x06,
/// <summary>Supplied Path ID is invalid</summary>
CamPathInvalid = 0x07,
/// <summary>SCSI Device Not Installed/there</summary>
CamDevNotThere = 0x08,
/// <summary>Unable to terminate I/O CCB request</summary>
CamUaTermio = 0x09,
/// <summary>Target Selection Timeout</summary>
CamSelTimeout = 0x0a,
/// <summary>Command timeout</summary>
CamCmdTimeout = 0x0b,
/// <summary>SCSI error, look at error code in CCB</summary>
CamScsiStatusError = 0x0c,
/// <summary>Message Reject Received</summary>
CamMsgRejectRec = 0x0d,
/// <summary>SCSI Bus Reset Sent/Received</summary>
CamScsiBusReset = 0x0e,
/// <summary>Uncorrectable parity error occurred</summary>
CamUncorParity = 0x0f,
/// <summary>Autosense: request sense cmd fail</summary>
CamAutosenseFail = 0x10,
/// <summary>No HBA Detected error</summary>
CamNoHba = 0x11,
/// <summary>Data Overrun error</summary>
CamDataRunErr = 0x12,
/// <summary>Unexpected Bus Free</summary>
CamUnexpBusfree = 0x13,
/// <summary>Target Bus Phase Sequence Failure</summary>
CamSequenceFail = 0x14,
/// <summary>CCB length supplied is inadequate</summary>
CamCcbLenErr = 0x15,
/// <summary>Unable to provide requested capability</summary>
CamProvideFail = 0x16,
/// <summary>A SCSI BDR msg was sent to target</summary>
CamBdrSent = 0x17,
/// <summary>CCB request terminated by the host</summary>
CamReqTermio = 0x18,
/// <summary>Unrecoverable Host Bus Adapter Error</summary>
CamUnrecHbaError = 0x19,
/// <summary>Request was too large for this host</summary>
CamReqTooBig = 0x1a,
/// <summary>
/// This request should be requeued to preserve transaction ordering. This typically occurs when the SIM
/// recognizes an error that should freeze the queue and must place additional requests for the target at the sim level
/// back into the XPT queue.
/// </summary>
CamRequeueReq = 0x1b,
/// <summary>ATA error, look at error code in CCB</summary>
CamAtaStatusError = 0x1c,
/// <summary>Initiator/Target Nexus lost.</summary>
CamScsiItNexusLost = 0x1d,
/// <summary>SMP error, look at error code in CCB</summary>
CamSmpStatusError = 0x1e,
/// <summary>Command completed without error but exceeded the soft timeout threshold.</summary>
CamReqSofttimeout = 0x1f,
/*
* 0x20 - 0x32 are unassigned
*/
/// <summary>Initiator Detected Error</summary>
CamIde = 0x33,
/// <summary>Resource Unavailable</summary>
CamResrcUnavail = 0x34,
/// <summary>Unacknowledged Event by Host</summary>
CamUnackedEvent = 0x35,
/// <summary>Message Received in Host Target Mode</summary>
CamMessageRecv = 0x36,
/// <summary>Invalid CDB received in Host Target Mode</summary>
CamInvalidCdb = 0x37,
/// <summary>Lun supplied is invalid</summary>
CamLunInvalid = 0x38,
/// <summary>Target ID supplied is invalid</summary>
CamTidInvalid = 0x39,
/// <summary>The requested function is not available</summary>
CamFuncNotavail = 0x3a,
/// <summary>Nexus is not established</summary>
CamNoNexus = 0x3b,
/// <summary>The initiator ID is invalid</summary>
CamIidInvalid = 0x3c,
/// <summary>The SCSI CDB has been received</summary>
CamCdbRecvd = 0x3d,
/// <summary>The LUN is already enabled for target mode</summary>
CamLunAlrdyEna = 0x3e,
/// <summary>SCSI Bus Busy</summary>
CamScsiBusy = 0x3f,
/*
* Flags
*/
/// <summary>The DEV queue is frozen w/this err</summary>
CamDevQfrzn = 0x40,
/// <summary>Autosense data valid for target</summary>
CamAutosnsValid = 0x80,
/// <summary>SIM ready to take more commands</summary>
CamReleaseSimq = 0x100,
/// <summary>SIM has this command in its queue</summary>
CamSimQueued = 0x200,
/// <summary>Quality of service data is valid</summary>
CamQosValid = 0x400,
/// <summary>Mask bits for just the status #</summary>
CamStatusMask = 0x3F,
/*
* Target Specific Adjunct Status
*/
/// <summary>sent sense with status</summary>
CamSentSense = 0x40000000
}
}

View File

@@ -0,0 +1,65 @@
// /***************************************************************************
// The Disc Image Chef
// ----------------------------------------------------------------------------
//
// Filename : Extern.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// Component : FreeBSD direct device access.
//
// --[ Description ] ----------------------------------------------------------
//
// Contains the P/Invoke definitions of FreeBSD syscalls used to directly
// interface devices.
//
// --[ License ] --------------------------------------------------------------
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 2.1 of the
// License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2020 Natalia Portillo
// ****************************************************************************/
using System;
using System.Runtime.InteropServices;
namespace DiscImageChef.Devices.FreeBSD
{
static class Extern
{
[DllImport("libc", CharSet = CharSet.Ansi, SetLastError = true)]
internal static extern int open(string pathname, [MarshalAs(UnmanagedType.U4)] FileFlags flags);
[DllImport("libc")]
internal static extern int close(int fd);
[DllImport("libcam", CharSet = CharSet.Ansi, SetLastError = true)]
internal static extern IntPtr cam_open_device(string path, [MarshalAs(UnmanagedType.U4)] FileFlags flags);
[DllImport("libcam", CharSet = CharSet.Ansi, SetLastError = true)]
internal static extern void cam_close_device(IntPtr dev);
[DllImport("libcam", CharSet = CharSet.Ansi, SetLastError = true)]
internal static extern IntPtr cam_getccb(IntPtr dev);
[DllImport("libcam", CharSet = CharSet.Ansi, SetLastError = true)]
internal static extern void cam_freeccb(IntPtr ccb);
[DllImport("libcam", CharSet = CharSet.Ansi, SetLastError = true)]
internal static extern int cam_send_ccb(IntPtr dev, IntPtr ccb);
[DllImport("libc")]
internal static extern int ioctl(int fd, FreebsdIoctl request, IntPtr argp);
}
}

View File

@@ -0,0 +1,166 @@
// /***************************************************************************
// The Disc Image Chef
// ----------------------------------------------------------------------------
//
// Filename : ListDevices.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// Component : FreeBSD direct device access.
//
// --[ Description ] ----------------------------------------------------------
//
// Gets a list of known devices.
//
// --[ License ] --------------------------------------------------------------
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 2.1 of the
// License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2020 Natalia Portillo
// ****************************************************************************/
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using DiscImageChef.CommonTypes.Structs.Devices.ATA;
using DiscImageChef.CommonTypes.Structs.Devices.SCSI;
using static DiscImageChef.Devices.FreeBSD.Extern;
namespace DiscImageChef.Devices.FreeBSD
{
internal static class ListDevices
{
/// <summary>Gets a list of all known storage devices on FreeBSD</summary>
/// <returns>List of devices</returns>
internal static DeviceInfo[] GetList()
{
string[] passDevices = Directory.GetFiles("/dev/", "pass*", SearchOption.TopDirectoryOnly);
List<DeviceInfo> listDevices = new List<DeviceInfo>();
foreach(string passDevice in passDevices)
{
var deviceInfo = new DeviceInfo();
IntPtr dev = cam_open_device(passDevice, FileFlags.ReadWrite);
var camDevice = (CamDevice)Marshal.PtrToStructure(dev, typeof(CamDevice));
IntPtr ccbPtr = cam_getccb(dev);
if(ccbPtr.ToInt64() == 0)
continue;
var cgd = (CcbGetdev)Marshal.PtrToStructure(ccbPtr, typeof(CcbGetdev));
cgd.ccb_h.func_code = XptOpcode.XptGdevType;
Marshal.StructureToPtr(cgd, ccbPtr, false);
int error = cam_send_ccb(dev, ccbPtr);
if(error < 0)
{
cam_freeccb(ccbPtr);
continue;
}
cgd = (CcbGetdev)Marshal.PtrToStructure(ccbPtr, typeof(CcbGetdev));
cam_freeccb(ccbPtr);
cam_close_device(dev);
string simName = StringHandlers.CToString(camDevice.SimName);
deviceInfo.Path = passDevice;
byte[] serialNumber = new byte[camDevice.SerialNumLen];
Array.Copy(camDevice.SerialNum, 0, serialNumber, 0, serialNumber.Length);
deviceInfo.Serial = StringHandlers.CToString(serialNumber);
switch(cgd.protocol)
{
case CamProto.ProtoAta:
case CamProto.ProtoAtapi:
case CamProto.ProtoSatapm:
{
// Little-endian FreeBSD gives it resorted
// Big-endian FreeBSD, no idea
byte[] atadTneid = new byte[512];
for(int aIndex = 0; aIndex < 512; aIndex += 2)
{
atadTneid[aIndex] = cgd.ident_data[aIndex + 1];
atadTneid[aIndex + 1] = cgd.ident_data[aIndex];
}
Identify.IdentifyDevice? idt = Identify.Decode(atadTneid);
if(idt.HasValue)
{
string[] separated = idt.Value.Model.Split(' ');
if(separated.Length == 1)
{
deviceInfo.Vendor = "ATA";
deviceInfo.Model = separated[0];
}
else
{
deviceInfo.Vendor = separated[0];
deviceInfo.Model = separated[separated.Length - 1];
}
deviceInfo.Serial = idt.Value.SerialNumber;
deviceInfo.Bus = simName == "ahcich" ? "SATA" : "ATA";
deviceInfo.Supported = simName != "ata";
}
if(cgd.protocol == CamProto.ProtoAtapi)
goto case CamProto.ProtoScsi;
break;
}
case CamProto.ProtoScsi:
{
Inquiry? inq = Inquiry.Decode(cgd.inq_data);
if(inq.HasValue)
{
deviceInfo.Vendor = StringHandlers.CToString(inq.Value.VendorIdentification).Trim();
deviceInfo.Model = StringHandlers.CToString(inq.Value.ProductIdentification).Trim();
deviceInfo.Bus = simName == "ata" || simName == "ahcich" ? "ATAPI" : "SCSI";
deviceInfo.Supported = simName != "ata";
}
break;
}
case CamProto.ProtoNvme:
deviceInfo.Bus = "NVMe";
deviceInfo.Supported = false;
break;
case CamProto.ProtoMmcsd:
deviceInfo.Model = "Unknown card";
deviceInfo.Bus = "MMC/SD";
deviceInfo.Supported = false;
break;
}
listDevices.Add(deviceInfo);
}
return listDevices.Count > 0 ? listDevices.OrderBy(t => t.Path).ToArray() : null;
}
}
}

View File

@@ -0,0 +1,883 @@
// /***************************************************************************
// The Disc Image Chef
// ----------------------------------------------------------------------------
//
// Filename : Structs.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// Component : FreeBSD direct device access.
//
// --[ Description ] ----------------------------------------------------------
//
// Contains structures necessary for directly interfacing devices under
// FreeBSD.
//
// --[ License ] --------------------------------------------------------------
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 2.1 of the
// License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2020 Natalia Portillo
// ****************************************************************************/
using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using lun_id_t = System.UInt32;
using path_id_t = System.UInt32;
using target_id_t = System.UInt32;
// ReSharper disable BuiltInTypeReferenceStyle
#pragma warning disable 649
#pragma warning disable 169
namespace DiscImageChef.Devices.FreeBSD
{
[StructLayout(LayoutKind.Sequential)]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
struct AtaCmd
{
public CamAtaIoFlags flags;
public byte command;
public byte features;
public byte lba_low;
public byte lba_mid;
public byte lba_high;
public byte device;
public byte lba_low_exp;
public byte lba_mid_exp;
public byte lba_high_exp;
public byte features_exp;
public byte sector_count;
public byte sector_count_exp;
public byte control;
}
[StructLayout(LayoutKind.Sequential)]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
struct AtaRes
{
public CamAtaIoFlags flags;
public byte status;
public byte error;
public byte lba_low;
public byte lba_mid;
public byte lba_high;
public byte device;
public byte lba_low_exp;
public byte lba_mid_exp;
public byte lba_high_exp;
public byte sector_count;
public byte sector_count_exp;
}
[StructLayout(LayoutKind.Sequential)]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
struct CamPinfo
{
public uint priority;
public uint generation;
public int index;
}
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
struct ListEntry
{
/// <summary>
/// LIST_ENTRY(ccb_hdr)=le->*le_next
/// </summary>
public IntPtr LeNext;
/// <summary>
/// LIST_ENTRY(ccb_hdr)=le->**le_prev
/// </summary>
public IntPtr LePrev;
}
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
struct SlistEntry
{
/// <summary>
/// SLIST_ENTRY(ccb_hdr)=sle->*sle_next
/// </summary>
public IntPtr SleNext;
}
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
struct TailqEntry
{
/// <summary>
/// TAILQ_ENTRY(ccb_hdr)=tqe->*tqe_next
/// </summary>
public IntPtr TqeNext;
/// <summary>
/// TAILQ_ENTRY(ccb_hdr)=tqe->**tqe_prev
/// </summary>
public IntPtr TqePrev;
}
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
struct StailqEntry
{
/// <summary>
/// STAILQ_ENTRY(ccb_hdr)=stqe->*stqe_next
/// </summary>
public IntPtr StqeNext;
}
[StructLayout(LayoutKind.Explicit)]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
struct CamqEntry
{
[FieldOffset(0)]
public ListEntry le;
[FieldOffset(0)]
public SlistEntry sle;
[FieldOffset(0)]
public TailqEntry tqe;
[FieldOffset(0)]
public StailqEntry stqe;
}
[StructLayout(LayoutKind.Sequential)]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
struct Timeval
{
public long tv_sec;
/// <summary>long</summary>
public IntPtr tv_usec;
}
[StructLayout(LayoutKind.Sequential)]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
struct CcbQosArea
{
public Timeval etime;
public UIntPtr sim_data;
public UIntPtr periph_data;
}
[StructLayout(LayoutKind.Sequential)]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
struct CcbHdr
{
public CamPinfo pinfo;
public CamqEntry xpt_links;
public CamqEntry sim_links;
public CamqEntry periph_links;
public uint retry_count;
public IntPtr cbfcnp;
public XptOpcode func_code;
public CamStatus status;
public IntPtr path;
public uint path_id;
public uint target_id;
public ulong target_lun;
public CcbFlags flags;
public uint xflags;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public IntPtr[] periph_priv;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public IntPtr[] sim_priv;
public CcbQosArea qos;
public uint timeout;
public Timeval softtimeout;
}
[StructLayout(LayoutKind.Sequential)]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
struct ScsiSenseData
{
const int SSD_FULL_SIZE = 252;
public byte error_code;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = SSD_FULL_SIZE - 1)]
public byte[] sense_buf;
}
/// <summary>
/// SCSI I/O Request CCB used for the XPT_SCSI_IO and XPT_CONT_TARGET_IO function codes.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
struct CcbScsiio
{
public CcbHdr ccb_h;
/// <summary>Ptr for next CCB for action</summary>
public IntPtr next_ccb;
/// <summary>Ptr to mapping info</summary>
public IntPtr req_map;
/// <summary>Ptr to the data buf/SG list</summary>
public IntPtr data_ptr;
/// <summary>Data transfer length</summary>
public uint dxfer_len;
/// <summary>Autosense storage</summary>
public ScsiSenseData sense_data;
/// <summary>Number of bytes to autosense</summary>
public byte sense_len;
/// <summary>Number of bytes for the CDB</summary>
public byte cdb_len;
/// <summary>Number of SG list entries</summary>
public short sglist_cnt;
/// <summary>Returned SCSI status</summary>
public byte scsi_status;
/// <summary>Autosense resid length: 2's comp</summary>
public sbyte sense_resid;
/// <summary>Transfer residual length: 2's comp</summary>
public int resid;
/// <summary>
/// Area for the CDB send, or pointer to the CDB bytes to send
/// </summary>
const int IOCDBLEN = 16;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = IOCDBLEN)]
public byte[] cdb_bytes;
/// <summary>Pointer to the message buffer</summary>
public IntPtr msg_ptr;
/// <summary>Number of bytes for the Message</summary>
public short msg_len;
/// <summary>
/// What to do for tag queueing. The tag action should be either the define below (to send a non-tagged
/// transaction) or one of the defined scsi tag messages from scsi_message.h.
/// </summary>
public byte tag_action;
/// <summary>tag id from initator (target mode)</summary>
public uint tag_id;
/// <summary>initiator id of who selected</summary>
public uint init_id;
}
/// <summary>
/// SCSI I/O Request CCB used for the XPT_SCSI_IO and XPT_CONT_TARGET_IO function codes.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
struct CcbScsiio64
{
public CcbHdr ccb_h;
/// <summary>Ptr for next CCB for action</summary>
public IntPtr next_ccb;
/// <summary>Ptr to mapping info</summary>
public IntPtr req_map;
/// <summary>Ptr to the data buf/SG list</summary>
public IntPtr data_ptr;
/// <summary>Data transfer length</summary>
public uint dxfer_len;
/// <summary>Autosense storage</summary>
public ScsiSenseData sense_data;
/// <summary>Number of bytes to autosense</summary>
public byte sense_len;
/// <summary>Number of bytes for the CDB</summary>
public byte cdb_len;
/// <summary>Number of SG list entries</summary>
public short sglist_cnt;
/// <summary>Returned SCSI status</summary>
public byte scsi_status;
/// <summary>Autosense resid length: 2's comp</summary>
public sbyte sense_resid;
/// <summary>Transfer residual length: 2's comp</summary>
public int resid;
public uint alignment;
/// <summary>
/// Area for the CDB send, or pointer to the CDB bytes to send
/// </summary>
const int IOCDBLEN = 16;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = IOCDBLEN)]
public byte[] cdb_bytes;
/// <summary>Pointer to the message buffer</summary>
public IntPtr msg_ptr;
/// <summary>Number of bytes for the Message</summary>
public short msg_len;
/// <summary>
/// What to do for tag queueing. The tag action should be either the define below (to send a non-tagged
/// transaction) or one of the defined scsi tag messages from scsi_message.h.
/// </summary>
public byte tag_action;
/// <summary>tag id from initator (target mode)</summary>
public uint tag_id;
/// <summary>initiator id of who selected</summary>
public uint init_id;
}
/// <summary>
/// ATA I/O Request CCB used for the XPT_ATA_IO function code.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
struct CcbAtaio
{
public CcbHdr ccb_h;
/// <summary>Ptr for next CCB for action</summary>
public IntPtr next_ccb;
/// <summary>ATA command register set</summary>
public AtaCmd cmd;
/// <summary>ATA result register set</summary>
public AtaRes res;
/// <summary>Ptr to the data buf/SG list</summary>
public IntPtr data_ptr;
/// <summary>Data transfer length</summary>
public uint dxfer_len;
/// <summary>Transfer residual length: 2's comp</summary>
public int resid;
/// <summary>Flags for the rest of the buffer</summary>
public byte ata_flags;
public uint aux;
public uint unused;
}
[StructLayout(LayoutKind.Sequential)]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
struct NvmeCommand
{
ushort opc_fuse_rsvd1;
/// <summary>
/// command identifier
/// </summary>
public ushort cid;
/// <summary>
/// namespace identifier
/// </summary>
public uint nsid;
/// <summary>
/// reserved
/// </summary>
public uint rsvd2;
/// <summary>
/// reserved
/// </summary>
public uint rsvd3;
/// <summary>
/// metadata pointer
/// </summary>
public ulong mptr;
/// <summary>
/// prp entry 1
/// </summary>
public ulong prp1;
/// <summary>
/// prp entry 2
/// </summary>
public ulong prp2;
/// <summary>
/// command-specific
/// </summary>
public uint cdw10;
/// <summary>
/// command-specific
/// </summary>
public uint cdw11;
/// <summary>
/// command-specific
/// </summary>
public uint cdw12;
/// <summary>
/// command-specific
/// </summary>
public uint cdw13;
/// <summary>
/// command-specific
/// </summary>
public uint cdw14;
/// <summary>
/// command-specific
/// </summary>
public uint cdw15;
/// <summary>
/// opcode
/// </summary>
public byte Opc => (byte)((opc_fuse_rsvd1 & 0xFF00) >> 8);
/// <summary>
/// fused operation
/// </summary>
public byte Fuse => (byte)((opc_fuse_rsvd1 & 0xC0) >> 6);
/// <summary>
/// reserved
/// </summary>
public byte Rsvd1 => (byte)(opc_fuse_rsvd1 & 0x3F);
}
[StructLayout(LayoutKind.Sequential)]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
struct NvmeStatus
{
ushort status;
/// <summary>
/// phase tag
/// </summary>
public byte P => (byte)((status & 0x8000) >> 15);
/// <summary>
/// status code
/// </summary>
public byte Sc => (byte)((status & 0x7F80) >> 7);
/// <summary>
/// status code type
/// </summary>
public byte Sct => (byte)((status & 0x70) >> 4);
/// <summary>
/// reserved
/// </summary>
public byte Rsvd2 => (byte)((status & 0xC) >> 15);
/// <summary>
/// more
/// </summary>
public byte M => (byte)((status & 0x2) >> 1);
/// <summary>
/// do not retry
/// </summary>
public byte Dnr => (byte)(status & 0x1);
}
[StructLayout(LayoutKind.Sequential)]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
struct NvmeCompletion
{
/// <summary>
/// command-specific
/// </summary>
public uint cdw0;
/// <summary>
/// reserved
/// </summary>
public uint rsvd1;
/// <summary>
/// submission queue head pointer
/// </summary>
public ushort sqhd;
/// <summary>
/// submission queue identifier
/// </summary>
public ushort sqid;
/// <summary>
/// command identifier
/// </summary>
public ushort cid;
public NvmeStatus status;
}
/// <summary>
/// NVMe I/O Request CCB used for the XPT_NVME_IO and XPT_NVME_ADMIN function codes.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
struct CcbNvmeio
{
public CcbHdr ccb_h;
/// <summary>Ptr for next CCB for action</summary>
public IntPtr next_ccb;
/// <summary>NVME command, per NVME standard</summary>
public NvmeCommand cmd;
/// <summary>NVME completion, per NVME standard</summary>
public NvmeCompletion cpl;
/// <summary>Ptr to the data buf/SG list</summary>
public IntPtr data_ptr;
/// <summary>Data transfer length</summary>
public uint dxfer_len;
/// <summary>Number of SG list entries</summary>
public ushort sglist_cnt;
/// <summary>padding for removed uint32_t</summary>
public ushort unused;
}
[StructLayout(LayoutKind.Sequential)]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
struct PeriphMatchPattern
{
const int DEV_IDLEN = 16;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = DEV_IDLEN)]
public byte[] periph_name;
public uint unit_number;
public path_id_t path_id;
public target_id_t target_id;
public lun_id_t target_lun;
public PeriphPatternFlags flags;
}
[StructLayout(LayoutKind.Sequential)]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
struct DeviceIdMatchPattern
{
public byte id_len;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
public byte[] id;
}
[StructLayout(LayoutKind.Sequential)]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
struct ScsiStaticInquiryPattern
{
const int SID_VENDOR_SIZE = 8;
const int SID_PRODUCT_SIZE = 16;
const int SID_REVISION_SIZE = 4;
public byte type;
public byte media_type;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = SID_VENDOR_SIZE + 1)]
public byte[] vendor;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = SID_PRODUCT_SIZE + 1)]
public byte[] product;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = SID_REVISION_SIZE + 1)]
public byte[] revision;
}
[StructLayout(LayoutKind.Explicit)]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
struct DeviceMatchPatternData
{
[FieldOffset(0)]
public ScsiStaticInquiryPattern inq_pat;
[FieldOffset(0)]
public DeviceIdMatchPattern devid_pat;
}
[StructLayout(LayoutKind.Sequential)]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
struct DeviceMatchPattern
{
public uint path_id;
public uint target_id;
public uint target_lun;
public DevPatternFlags flags;
public DeviceMatchPatternData data;
}
[StructLayout(LayoutKind.Sequential)]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
struct BusMatchPattern
{
const int DEV_IDLEN = 16;
public path_id_t path_id;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = DEV_IDLEN)]
public byte[] dev_name;
public uint unit_number;
public uint bus_id;
BusPatternFlags flags;
}
[StructLayout(LayoutKind.Explicit)]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
struct MatchPattern
{
[FieldOffset(0)]
public PeriphMatchPattern periph_pattern;
[FieldOffset(0)]
public DeviceMatchPattern device_pattern;
[FieldOffset(0)]
public BusMatchPattern bus_pattern;
}
[StructLayout(LayoutKind.Sequential)]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
struct DevMatchPattern
{
public DevMatchType type;
public MatchPattern pattern;
}
[StructLayout(LayoutKind.Sequential)]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
struct PeriphMatchResult
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public byte[] periph_name;
public uint unit_number;
public path_id_t path_id;
public target_id_t target_id;
public lun_id_t target_lun;
}
[StructLayout(LayoutKind.Sequential)]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
struct MmcCid
{
public uint mid;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] pnm;
public uint psn;
public ushort oid;
public ushort mdt_year;
public byte mdt_month;
public byte prv;
public byte fwrev;
}
[StructLayout(LayoutKind.Sequential)]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
struct MmcParams
{
/// <summary>
/// Card model
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)]
public byte[] model;
/// <summary>
/// Card OCR
/// </summary>
public uint card_ocr;
/// <summary>
/// OCR of the IO portion of the card
/// </summary>
public uint io_ocr;
/// <summary>
/// Card CID -- raw
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public uint[] card_cid;
/// <summary>
/// Card CID -- parsed
/// </summary>
public MmcCid cid;
/// <summary>
/// Card CSD -- raw
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public uint[] card_csd;
/// <summary>
/// Card RCA
/// </summary>
public ushort card_rca;
/// <summary>
/// What kind of card is it
/// </summary>
public MmcCardFeatures card_features;
public byte sdio_func_count;
}
[StructLayout(LayoutKind.Sequential)]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
struct DeviceMatchResult
{
public path_id_t path_id;
public target_id_t target_id;
public lun_id_t target_lun;
public CamProto protocol;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
public byte[] inq_data;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)]
public byte[] ident_data;
public DevResultFlags flags;
public MmcParams mmc_ident_data;
}
[StructLayout(LayoutKind.Sequential)]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
struct BusMatchResult
{
public path_id_t path_id;
const int DEV_IDLEN = 16;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = DEV_IDLEN)]
public byte[] dev_name;
public uint unit_number;
public uint bus_id;
}
[StructLayout(LayoutKind.Explicit)]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
struct MatchResult
{
[FieldOffset(0)]
public PeriphMatchResult periph_result;
[FieldOffset(0)]
public DeviceMatchResult device_result;
[FieldOffset(0)]
public BusMatchResult bus_result;
}
[StructLayout(LayoutKind.Sequential)]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
struct DevMatchResult
{
public DevMatchType type;
public MatchResult result;
}
[StructLayout(LayoutKind.Sequential)]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
struct CcbDmCookie
{
public IntPtr bus;
public IntPtr target;
public IntPtr device;
public IntPtr periph;
public IntPtr pdrv;
}
[StructLayout(LayoutKind.Sequential)]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
struct CcbDevPosition
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public CamGenerations[] generations;
DevPosType position_type;
public CcbDmCookie cookie;
}
[StructLayout(LayoutKind.Sequential)]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
struct CcbDevMatch
{
public CcbHdr ccb_h;
CcbDevMatchStatus status;
public uint num_patterns;
public uint pattern_buf_len;
/// <summary>
/// dev_match_pattern*
/// </summary>
public IntPtr patterns;
public uint num_matches;
public uint match_buf_len;
/// <summary>
/// dev_match_result*
/// </summary>
public IntPtr matches;
public CcbDevPosition pos;
}
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
struct CamDevice
{
const int MAXPATHLEN = 1024;
const int DEV_IDLEN = 16;
const int SIM_IDLEN = 16;
/// <summary>
/// Pathname of the device given by the user. This may be null if the user states the device name and unit number
/// separately.
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MAXPATHLEN)]
public byte[] DevicePath;
/// <summary>
/// Device name given by the user.
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = DEV_IDLEN + 1)]
public byte[] GivenDevName;
/// <summary>
/// Unit number given by the user.
/// </summary>
public uint GivenUnitNumber;
/// <summary>
/// Name of the device, e.g. 'pass'
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = DEV_IDLEN + 1)]
public byte[] DeviceName;
/// <summary>
/// Unit number of the passthrough device associated with this particular device.
/// </summary>
public uint DevUnitNum;
/// <summary>
/// Controller name, e.g. 'ahc'
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = SIM_IDLEN + 1)]
public byte[] SimName;
/// <summary>
/// Controller unit number
/// </summary>
public uint SimUnitNumber;
/// <summary>
/// Controller bus number
/// </summary>
public uint BusId;
/// <summary>
/// Logical Unit Number
/// </summary>
public lun_id_t TargetLun;
/// <summary>
/// Target ID
/// </summary>
public target_id_t TargetId;
/// <summary>
/// System SCSI bus number
/// </summary>
public path_id_t PathId;
/// <summary>
/// type of peripheral device
/// </summary>
public ushort PdType;
/// <summary>
/// SCSI Inquiry data
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
public byte[] InqData;
/// <summary>
/// device serial number
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 252)]
public byte[] SerialNum;
/// <summary>
/// length of the serial number
/// </summary>
public byte SerialNumLen;
/// <summary>
/// Negotiated sync period
/// </summary>
public byte SyncPeriod;
/// <summary>
/// Negotiated sync offset
/// </summary>
public byte SyncOffset;
/// <summary>
/// Negotiated bus width
/// </summary>
public byte BusWidth;
/// <summary>
/// file descriptor for device
/// </summary>
public int Fd;
}
[StructLayout(LayoutKind.Sequential)]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
struct CcbGetdev
{
public CcbHdr ccb_h;
public CamProto protocol;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
public byte[] inq_data;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)]
public byte[] ident_data;
/// <summary>
/// device serial number
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 252)]
public byte[] serial_num;
public byte inq_flags;
/// <summary>
/// length of the serial number
/// </summary>
public byte serial_num_len;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public IntPtr[] padding;
}
}