How to use the DataBuffer of SCSI_PASS_THROUGH_DIRECT in c# ?

  • Thread starter Thread starter Marce
  • Start date Start date
M

Marce

Hi All;

I need to send a READ command to CD-ROM drive by SCSI_PASS_THROUGH_DIRECT.

int inputSize = Marshal.SizeOf(typeof(SCSI_PASS_THROUGH_WITH_BUFFERS));
IntPtr input = Marshal.AllocHGlobal(inputSize);
Marshal.StructureToPtr(sptdwb, input, true)


In my code, the Marshal.StructureToPtr(sptdwb, input, true) will return
error, because the sptdwb and input size are not equal, then the PVOID
DataBuffer can't be access.

Do you have any ideas ?
 
Sorry, modify some message.


I need to send a READ command to CD-ROM drive by SCSI_PASS_THROUGH_DIRECT.
As SCSI_PASS_THROUGH_DIRECT struct:

typedef struct _SCSI_PASS_THROUGH_DIRECT {
USHORT Length;
UCHAR ScsiStatus;
UCHAR PathId;
UCHAR TargetId;
UCHAR Lun;
UCHAR CdbLength;
UCHAR SenseInfoLength;
UCHAR DataIn;
ULONG DataTransferLength;
ULONG TimeOutValue;
PVOID DataBuffer;
ULONG SenseInfoOffset;
UCHAR Cdb[16];
}SCSI_PASS_THROUGH_DIRECT, *PSCSI_PASS_THROUGH_DIRECT;


int inputSize = Marshal.SizeOf(typeof(SCSI_PASS_THROUGH_WITH_BUFFERS));
IntPtr input = Marshal.AllocHGlobal(inputSize);
Marshal.StructureToPtr(sptdwb, input, true)


In my code, the Marshal.StructureToPtr(sptdwb, input, true) will return
error, because I need to modify the DataBuffer size for each command, the
sptdwb and input size will not equal, then the PVOID DataBuffer can't be
access.

Do you have any ideas ?

Thank you for your help !!
 
Marce said:
Sorry, modify some message.


I need to send a READ command to CD-ROM drive by
SCSI_PASS_THROUGH_DIRECT.
As SCSI_PASS_THROUGH_DIRECT struct:

typedef struct _SCSI_PASS_THROUGH_DIRECT {
USHORT Length;
UCHAR ScsiStatus;
UCHAR PathId;
UCHAR TargetId;
UCHAR Lun;
UCHAR CdbLength;
UCHAR SenseInfoLength;
UCHAR DataIn;
ULONG DataTransferLength;
ULONG TimeOutValue;
PVOID DataBuffer;
ULONG SenseInfoOffset;
UCHAR Cdb[16];
}SCSI_PASS_THROUGH_DIRECT, *PSCSI_PASS_THROUGH_DIRECT;


int inputSize = Marshal.SizeOf(typeof(SCSI_PASS_THROUGH_WITH_BUFFERS));
IntPtr input = Marshal.AllocHGlobal(inputSize);
Marshal.StructureToPtr(sptdwb, input, true)


In my code, the Marshal.StructureToPtr(sptdwb, input, true) will return
error, because I need to modify the DataBuffer size for each command, the
sptdwb and input size will not equal, then the PVOID DataBuffer can't be
access.

Do you have any ideas ?

Thank you for your help !!



We need your SCSI_PASS_THROUGH_DIRECT structure declaration in C# to help
you with this.

Willy.
 
Willy said:
Sorry, modify some message.
[quoted text clipped - 30 lines]
Thank you for your help !!

We need your SCSI_PASS_THROUGH_DIRECT structure declaration in C# to help
you with this.

Willy.
Thank you Willy!

[StructLayout(LayoutKind.Sequential)]
class SCSI_PASS_THROUGH_DIRECT
{

public UInt16 Length = (UInt16)Marshal.SizeOf(typeof
(SCSI_PASS_THROUGH_DIRECT));
public byte ScsiStatus = 0;
public byte PathId= 0;
public byte TargetId= 0;
public byte Lun = 0;
public byte CdbLength = 12;
public byte SenseInfoLength = 24;
public byte DataIn ;
public Int32 DataTransferLength;
public Int32 TimeOutValue= 30;
public IntPtr DataBuffer;
public UInt32 SenseInfoOffset = (UInt32)Marshal.OffsetOf(typeof
(SCSI_PASS_THROUGH_WITH_BUFFERS), "ucSenseBuf");
[MarshalAs(UnmanagedType.ByValArray,SizeConst = 16)]
public byte[] Cdb = new byte[16];
}

FYI.
 
Marce said:
[quoted text clipped - 6 lines]
Thank you Willy!

[StructLayout(LayoutKind.Sequential)]
class SCSI_PASS_THROUGH_DIRECT
{

public UInt16 Length = (UInt16)Marshal.SizeOf(typeof
(SCSI_PASS_THROUGH_DIRECT));
public byte ScsiStatus = 0;
public byte PathId= 0;
public byte TargetId= 0;
public byte Lun = 0;
public byte CdbLength = 12;
public byte SenseInfoLength = 24;
public byte DataIn ;
public Int32 DataTransferLength;
public Int32 TimeOutValue= 30;
public IntPtr DataBuffer;
public UInt32 SenseInfoOffset = (UInt32)Marshal.OffsetOf(typeof
(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFERS), "ucSenseBuf");
[MarshalAs(UnmanagedType.ByValArray,SizeConst = 16)]
public byte[] Cdb = new byte[16];
}

FYI.
 
Sorry, modify some error message !

[StructLayout(LayoutKind.Sequential)]
class SCSI_PASS_THROUGH_DIRECT
{

public UInt16 Length = (UInt16)Marshal.SizeOf(typeof
(SCSI_PASS_THROUGH_DIRECT));
public byte ScsiStatus = 0;
public byte PathId= 0;
public byte TargetId= 0;
public byte Lun = 0;
public byte CdbLength = 12;
public byte SenseInfoLength = 24;
public byte DataIn ;
public Int32 DataTransferLength;
public Int32 TimeOutValue= 30;
public IntPtr DataBuffer;
public UInt32 SenseInfoOffset = (UInt32)Marshal.OffsetOf(typeof
(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFERS), "ucSenseBuf");
[MarshalAs(UnmanagedType.ByValArray,SizeConst = 16)]
public byte[] Cdb = new byte[16];
}
 
Marce via DotNetMonster.com said:
Sorry, modify some error message !

[StructLayout(LayoutKind.Sequential)]
class SCSI_PASS_THROUGH_DIRECT
{

public UInt16 Length = (UInt16)Marshal.SizeOf(typeof
(SCSI_PASS_THROUGH_DIRECT));
public byte ScsiStatus = 0;
public byte PathId= 0;
public byte TargetId= 0;
public byte Lun = 0;
public byte CdbLength = 12;
public byte SenseInfoLength = 24;
public byte DataIn ;
public Int32 DataTransferLength;
public Int32 TimeOutValue= 30;
public IntPtr DataBuffer;
public UInt32 SenseInfoOffset = (UInt32)Marshal.OffsetOf(typeof
(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFERS), "ucSenseBuf");
[MarshalAs(UnmanagedType.ByValArray,SizeConst = 16)]
public byte[] Cdb = new byte[16];
}



You have to take care that you pass a correctly filled and aligned
structure, the buffers need to be fields in the same marshaled structure
(here SCSI_PASS_THROUGH_WITH_BUFFERS).

Here is how you could declare the structure and the
SCSI_PASS_THROUGH_WITH_BUFFERS class.

[StructLayout(LayoutKind.Sequential)]
struct SCSI_PASS_THROUGH_DIRECT
{
public short Length;
public byte ScsiStatus;
public byte PathId;
public byte TargetId;
public byte Lun;
public byte CdbLength;
public byte SenseInfoLength;
public byte DataIn ;
public int DataTransferLength;
public int TimeOutValue;
public IntPtr DataBufferOffset;
public uint SenseInfoOffset;
[MarshalAs(UnmanagedType.ByValArray,SizeConst = 16)]
public byte[] Cdb;
};

[StructLayout(LayoutKind.Sequential)]
class SCSI_PASS_THROUGH_WITH_BUFFERS
{
internal SCSI_PASS_THROUGH_DIRECT sptd = new SCSI_PASS_THROUGH_DIRECT();
// // adapt size to suit your needs!!!!!!
[MarshalAs(UnmanagedType.ByValArray,SizeConst = 18)]
internal byte[] sense ;
// adapt to suit your needs!!!!!!!
[MarshalAs(UnmanagedType.ByValArray,SizeConst = 36)]
internal byte[] data ;
};


// usage ...

SCSI_PASS_THROUGH_WITH_BUFFERS info = new
SCSI_PASS_THROUGH_WITH_BUFFERS();
info.sptd.Cdb = new byte[16];
info.sense = new byte[18]; // adapt to suit your needs!!!!!!
info.data = new byte[36]; // adapt to suit your needs!!!!!!

info.sptd.Length = (short)Marshal.SizeOf(info.sptd);
info.sptd.SenseInfoOffset =
(uint)Marshal.OffsetOf(typeof(SCSI_PASS_THROUGH_WITH_BUFFERS), "sense");
info.sptd.SenseInfoLength = (byte)info.sense.Length;
info.sptd.DataTransferLength = info.data.Length;
info.sptd.DataBufferOffset =
Marshal.OffsetOf(typeof(SCSI_PASS_THROUGH_WITH_BUFFERS), "data");
info.sptd.TimeOutValue = 30;
info.sptd.DataIn = SCSI_IOCTL_DATA_IN;
// initilalize the cdb
info.sptd.CdbLength = x; // length of CDB
info.sptd.Cdb[0] = ...;
....

IntPtr inpBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(info));
Marshal.StructureToPtr(info, inpBuffer, false);
// call DeviceIoControl passing the buffer inpBuffer as inp buffer
and/or output buffer depending on the command.
int ret = DeviceIoControl(...., inpBuffer, Marshal.SizeOf(info), ...);
....

Willy.
 
Willy said:
Sorry, modify some error message !
[quoted text clipped - 19 lines]
public byte[] Cdb = new byte[16];
}

You have to take care that you pass a correctly filled and aligned
structure, the buffers need to be fields in the same marshaled structure
(here SCSI_PASS_THROUGH_WITH_BUFFERS).

Here is how you could declare the structure and the
SCSI_PASS_THROUGH_WITH_BUFFERS class.

[StructLayout(LayoutKind.Sequential)]
struct SCSI_PASS_THROUGH_DIRECT
{
public short Length;
public byte ScsiStatus;
public byte PathId;
public byte TargetId;
public byte Lun;
public byte CdbLength;
public byte SenseInfoLength;
public byte DataIn ;
public int DataTransferLength;
public int TimeOutValue;
public IntPtr DataBufferOffset;
public uint SenseInfoOffset;
[MarshalAs(UnmanagedType.ByValArray,SizeConst = 16)]
public byte[] Cdb;
};

[StructLayout(LayoutKind.Sequential)]
class SCSI_PASS_THROUGH_WITH_BUFFERS
{
internal SCSI_PASS_THROUGH_DIRECT sptd = new SCSI_PASS_THROUGH_DIRECT();
// // adapt size to suit your needs!!!!!!
[MarshalAs(UnmanagedType.ByValArray,SizeConst = 18)]
internal byte[] sense ;
// adapt to suit your needs!!!!!!!
[MarshalAs(UnmanagedType.ByValArray,SizeConst = 36)]
internal byte[] data ;
};

// usage ...

SCSI_PASS_THROUGH_WITH_BUFFERS info = new
SCSI_PASS_THROUGH_WITH_BUFFERS();
info.sptd.Cdb = new byte[16];
info.sense = new byte[18]; // adapt to suit your needs!!!!!!
info.data = new byte[36]; // adapt to suit your needs!!!!!!

info.sptd.Length = (short)Marshal.SizeOf(info.sptd);
info.sptd.SenseInfoOffset =
(uint)Marshal.OffsetOf(typeof(SCSI_PASS_THROUGH_WITH_BUFFERS), "sense");
info.sptd.SenseInfoLength = (byte)info.sense.Length;
info.sptd.DataTransferLength = info.data.Length;
info.sptd.DataBufferOffset =
Marshal.OffsetOf(typeof(SCSI_PASS_THROUGH_WITH_BUFFERS), "data");
info.sptd.TimeOutValue = 30;
info.sptd.DataIn = SCSI_IOCTL_DATA_IN;
// initilalize the cdb
info.sptd.CdbLength = x; // length of CDB
info.sptd.Cdb[0] = ...;
....

IntPtr inpBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(info));
Marshal.StructureToPtr(info, inpBuffer, false);
// call DeviceIoControl passing the buffer inpBuffer as inp buffer
and/or output buffer depending on the command.
int ret = DeviceIoControl(...., inpBuffer, Marshal.SizeOf(info), ...);
...

Willy.
Thanks Willy.

It works ok by SCSI_PASS_THROUGH_WITH_BUFFERS, and the data buffer size need
to fixed.
As this:
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 30*2048)]
public byte[] ucDataBuf = new byte[30 * 2048];

But In the SCSI_PASS_THROUGH_DIRECT_BUFFERS structure, the DataBuffer is
IntPtr point.
How can I send a ATAPI cmd with databuffer by
SCSI_PASS_THROUGH_DIRECT_BUFFERS ?
 
Marce via DotNetMonster.com said:
Willy said:
Sorry, modify some error message !
[quoted text clipped - 19 lines]
public byte[] Cdb = new byte[16];
}

You have to take care that you pass a correctly filled and aligned
structure, the buffers need to be fields in the same marshaled structure
(here SCSI_PASS_THROUGH_WITH_BUFFERS).

Here is how you could declare the structure and the
SCSI_PASS_THROUGH_WITH_BUFFERS class.

[StructLayout(LayoutKind.Sequential)]
struct SCSI_PASS_THROUGH_DIRECT
{
public short Length;
public byte ScsiStatus;
public byte PathId;
public byte TargetId;
public byte Lun;
public byte CdbLength;
public byte SenseInfoLength;
public byte DataIn ;
public int DataTransferLength;
public int TimeOutValue;
public IntPtr DataBufferOffset;
public uint SenseInfoOffset;
[MarshalAs(UnmanagedType.ByValArray,SizeConst = 16)]
public byte[] Cdb;
};

[StructLayout(LayoutKind.Sequential)]
class SCSI_PASS_THROUGH_WITH_BUFFERS
{
internal SCSI_PASS_THROUGH_DIRECT sptd = new SCSI_PASS_THROUGH_DIRECT();
// // adapt size to suit your needs!!!!!!
[MarshalAs(UnmanagedType.ByValArray,SizeConst = 18)]
internal byte[] sense ;
// adapt to suit your needs!!!!!!!
[MarshalAs(UnmanagedType.ByValArray,SizeConst = 36)]
internal byte[] data ;
};

// usage ...

SCSI_PASS_THROUGH_WITH_BUFFERS info = new
SCSI_PASS_THROUGH_WITH_BUFFERS();
info.sptd.Cdb = new byte[16];
info.sense = new byte[18]; // adapt to suit your needs!!!!!!
info.data = new byte[36]; // adapt to suit your needs!!!!!!

info.sptd.Length = (short)Marshal.SizeOf(info.sptd);
info.sptd.SenseInfoOffset =
(uint)Marshal.OffsetOf(typeof(SCSI_PASS_THROUGH_WITH_BUFFERS), "sense");
info.sptd.SenseInfoLength = (byte)info.sense.Length;
info.sptd.DataTransferLength = info.data.Length;
info.sptd.DataBufferOffset =
Marshal.OffsetOf(typeof(SCSI_PASS_THROUGH_WITH_BUFFERS), "data");
info.sptd.TimeOutValue = 30;
info.sptd.DataIn = SCSI_IOCTL_DATA_IN;
// initilalize the cdb
info.sptd.CdbLength = x; // length of CDB
info.sptd.Cdb[0] = ...;
....

IntPtr inpBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(info));
Marshal.StructureToPtr(info, inpBuffer, false);
// call DeviceIoControl passing the buffer inpBuffer as inp buffer
and/or output buffer depending on the command.
int ret = DeviceIoControl(...., inpBuffer, Marshal.SizeOf(info), ...);
...

Willy.
Thanks Willy.

It works ok by SCSI_PASS_THROUGH_WITH_BUFFERS, and the data buffer size
need
to fixed.
As this:
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 30*2048)]
public byte[] ucDataBuf = new byte[30 * 2048];

But In the SCSI_PASS_THROUGH_DIRECT_BUFFERS structure, the DataBuffer is
IntPtr point.
How can I send a ATAPI cmd with databuffer by
SCSI_PASS_THROUGH_DIRECT_BUFFERS ?


Ok, if you need to pass such large buffers you will have to use the
IOCTL_SCSI_PASS_THROUGH_DIRECT ioctl command and define your structures as
follows:

[StructLayout(LayoutKind.Sequential)]
struct SCSI_PASS_THROUGH_DIRECT
{
public short Length;
public byte ScsiStatus;
public byte PathId;
public byte TargetId;
public byte Lun;
public byte CdbLength;
public byte SenseInfoLength;
public byte DataIn ;
public int DataTransferLength;
public int TimeOutValue;
public IntPtr DataBuffer; // note this is now interpreted as a
pointer, not an offset!!
public uint SenseInfoOffset;
[MarshalAs(UnmanagedType.ByValArray,SizeConst = 16)]
public byte[] Cdb;
};
[StructLayout(LayoutKind.Sequential)]
class SCSI_PASS_THROUGH_DIRECT_WITH_BUFFERS
{
internal SCSI_PASS_THROUGH_DIRECT sptd = new SCSI_PASS_THROUGH_DIRECT();
[MarshalAs(UnmanagedType.ByValArray,SizeConst = 18)]
internal byte[] sense ;
};



in your code, you'll have to allocate the data buffer like this:

SCSI_PASS_THROUGH_DIRECT_WITH_BUFFERS info = new
SCSI_PASS_THROUGH_DIRECT_WITH_BUFFERS();
....
info.sptd.DataBuffer = Marshal.AllocHGlobal(30 * 2048); // allocate
correctly aligned buffer

marshal the data to/from the buffer using Marshal.Copy, and...
use the IOCTL_SCSI_PASS_THROUGH_DIRECT command in the call to the
DeviceIOControl API like this:

const int IOCTL_SCSI_PASS_THROUGH_DIRECT = 0x4D014; // IOCTL cmd
....
DeviceIoControl(fh, IOCTL_SCSI_PASS_THROUGH_DIRECT,....

don't forget to Marshal.FreeHGlobal when done with the unmanaged buffer!!

Willy.
 
Dear Willy:
Thank you for your help!
This help me more !
[quoted text clipped - 83 lines]
How can I send a ATAPI cmd with databuffer by
SCSI_PASS_THROUGH_DIRECT_BUFFERS ?

Ok, if you need to pass such large buffers you will have to use the
IOCTL_SCSI_PASS_THROUGH_DIRECT ioctl command and define your structures as
follows:

[StructLayout(LayoutKind.Sequential)]
struct SCSI_PASS_THROUGH_DIRECT
{
public short Length;
public byte ScsiStatus;
public byte PathId;
public byte TargetId;
public byte Lun;
public byte CdbLength;
public byte SenseInfoLength;
public byte DataIn ;
public int DataTransferLength;
public int TimeOutValue;
public IntPtr DataBuffer; // note this is now interpreted as a
pointer, not an offset!!
public uint SenseInfoOffset;
[MarshalAs(UnmanagedType.ByValArray,SizeConst = 16)]
public byte[] Cdb;
};
[StructLayout(LayoutKind.Sequential)]
class SCSI_PASS_THROUGH_DIRECT_WITH_BUFFERS
{
internal SCSI_PASS_THROUGH_DIRECT sptd = new SCSI_PASS_THROUGH_DIRECT();
[MarshalAs(UnmanagedType.ByValArray,SizeConst = 18)]
internal byte[] sense ;
};

in your code, you'll have to allocate the data buffer like this:

SCSI_PASS_THROUGH_DIRECT_WITH_BUFFERS info = new
SCSI_PASS_THROUGH_DIRECT_WITH_BUFFERS();
...
info.sptd.DataBuffer = Marshal.AllocHGlobal(30 * 2048); // allocate
correctly aligned buffer

marshal the data to/from the buffer using Marshal.Copy, and...
use the IOCTL_SCSI_PASS_THROUGH_DIRECT command in the call to the
DeviceIOControl API like this:

const int IOCTL_SCSI_PASS_THROUGH_DIRECT = 0x4D014; // IOCTL cmd
...
DeviceIoControl(fh, IOCTL_SCSI_PASS_THROUGH_DIRECT,....

don't forget to Marshal.FreeHGlobal when done with the unmanaged buffer!!

Willy.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Back
Top