Ejemplo n.º 1
0
        /// <summary>Sends a SCSI command</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="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>
        /// <exception cref="InvalidOperationException">If the specified platform is not supported</exception>
        internal static int SendScsiCommand(PlatformID ptId, object fd, byte[] cdb, ref byte[] buffer,
                                            out byte[] senseBuffer, uint timeout, ScsiDirection direction,
                                            out double duration, out bool sense)
        {
            switch (ptId)
            {
            case PlatformID.Win32NT:
            {
                ScsiIoctlDirection dir;

                switch (direction)
                {
                case ScsiDirection.In:
                    dir = ScsiIoctlDirection.In;

                    break;

                case ScsiDirection.Out:
                    dir = ScsiIoctlDirection.Out;

                    break;

                default:
                    dir = ScsiIoctlDirection.Unspecified;

                    break;
                }

                return(Windows.Command.SendScsiCommand((SafeFileHandle)fd, cdb, ref buffer, out senseBuffer,
                                                       timeout, dir, out duration, out sense));
            }

            case PlatformID.Linux:
            {
                Linux.ScsiIoctlDirection dir;

                switch (direction)
                {
                case ScsiDirection.In:
                    dir = Linux.ScsiIoctlDirection.In;

                    break;

                case ScsiDirection.Out:
                    dir = Linux.ScsiIoctlDirection.Out;

                    break;

                case ScsiDirection.Bidirectional:
                    dir = Linux.ScsiIoctlDirection.Unspecified;

                    break;

                case ScsiDirection.None:
                    dir = Linux.ScsiIoctlDirection.None;

                    break;

                default:
                    dir = Linux.ScsiIoctlDirection.Unknown;

                    break;
                }

                return(Linux.Command.SendScsiCommand((int)fd, cdb, ref buffer, out senseBuffer, timeout, dir,
                                                     out duration, out sense));
            }

            case PlatformID.FreeBSD:
            {
                CcbFlags flags = 0;

                switch (direction)
                {
                case ScsiDirection.In:
                    flags = CcbFlags.CamDirIn;

                    break;

                case ScsiDirection.Out:
                    flags = CcbFlags.CamDirOut;

                    break;

                case ScsiDirection.Bidirectional:
                    flags = CcbFlags.CamDirBoth;

                    break;

                case ScsiDirection.None:
                    flags = CcbFlags.CamDirNone;

                    break;
                }

                return(IntPtr.Size == 8
                               ? FreeBSD.Command.SendScsiCommand64((IntPtr)fd, cdb, ref buffer, out senseBuffer,
                                                                   timeout, flags, out duration, out sense)
                               : FreeBSD.Command.SendScsiCommand((IntPtr)fd, cdb, ref buffer, out senseBuffer, timeout,
                                                                 flags, out duration, out sense));
            }

            default: throw new InvalidOperationException($"Platform {ptId} not yet supported.");
            }
        }
Ejemplo n.º 2
0
        /// <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());
            }

            var 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();
                AaruConsole.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);
        }