/// <summary>Sends a SCSI command</summary> /// <returns>0 if no error occurred, otherwise, errno</returns> /// <param name="fd">File handle</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(int fd, byte[] cdb, ref byte[] buffer, out byte[] senseBuffer, uint timeout, ScsiIoctlDirection direction, out double duration, out bool sense) { senseBuffer = null; duration = 0; sense = false; if (buffer == null) { return(-1); } var ioHdr = new SgIoHdrT(); senseBuffer = new byte[32]; ioHdr.interface_id = 'S'; ioHdr.cmd_len = (byte)cdb.Length; ioHdr.mx_sb_len = (byte)senseBuffer.Length; ioHdr.dxfer_direction = direction; ioHdr.dxfer_len = (uint)buffer.Length; ioHdr.dxferp = Marshal.AllocHGlobal(buffer.Length); ioHdr.cmdp = Marshal.AllocHGlobal(cdb.Length); ioHdr.sbp = Marshal.AllocHGlobal(senseBuffer.Length); ioHdr.timeout = timeout * 1000; ioHdr.flags = (uint)SgFlags.DirectIo; Marshal.Copy(buffer, 0, ioHdr.dxferp, buffer.Length); Marshal.Copy(cdb, 0, ioHdr.cmdp, cdb.Length); Marshal.Copy(senseBuffer, 0, ioHdr.sbp, senseBuffer.Length); DateTime start = DateTime.UtcNow; int error = Extern.ioctlSg(fd, LinuxIoctl.SgIo, ref ioHdr); DateTime end = DateTime.UtcNow; if (error < 0) { error = Marshal.GetLastWin32Error(); } Marshal.Copy(ioHdr.dxferp, buffer, 0, buffer.Length); Marshal.Copy(ioHdr.cmdp, cdb, 0, cdb.Length); Marshal.Copy(ioHdr.sbp, senseBuffer, 0, senseBuffer.Length); sense |= (ioHdr.info & SgInfo.OkMask) != SgInfo.Ok; duration = ioHdr.duration > 0 ? ioHdr.duration : (end - start).TotalMilliseconds; Marshal.FreeHGlobal(ioHdr.dxferp); Marshal.FreeHGlobal(ioHdr.cmdp); Marshal.FreeHGlobal(ioHdr.sbp); return(error); }
internal static extern int ioctlSg(int fd, LinuxIoctl request, ref SgIoHdrT value);