Implementation of IOCTL_SCSI_PASS_THROUGH and
IOCTL_SCSI_PASS_THROUGH_DIRECT.

diff --git a/configure b/configure
index 8339bea..cdf3eb8 100755
--- a/configure
+++ b/configure
@@ -10466,6 +10466,7 @@
 
 
 
+
 for ac_header in \
 	arpa/inet.h \
 	arpa/nameser.h \
@@ -10480,6 +10481,7 @@
 	linux/cdrom.h \
 	linux/input.h \
 	linux/joystick.h \
+	linux/param.h \
 	linux/serial.h \
 	linux/ucdrom.h \
 	net/if.h \
diff --git a/configure.ac b/configure.ac
index 91267fc..b36fb68 100644
--- a/configure.ac
+++ b/configure.ac
@@ -915,6 +915,7 @@
 	linux/cdrom.h \
 	linux/input.h \
 	linux/joystick.h \
+	linux/param.h \
 	linux/serial.h \
 	linux/ucdrom.h \
 	net/if.h \
diff --git a/dlls/ntdll/cdrom.c b/dlls/ntdll/cdrom.c
index 79137c9..63360c8 100644
--- a/dlls/ntdll/cdrom.c
+++ b/dlls/ntdll/cdrom.c
@@ -31,10 +31,14 @@
 #include "winioctl.h"
 #include "ntddstor.h"
 #include "ntddcdrm.h"
+#include "ntddscsi.h"
 #include "drive.h"
 #include "file.h"
 #include "wine/debug.h"
 
+#ifdef HAVE_LINUX_PARAM_H
+# include <linux/param.h>
+#endif
 #ifdef HAVE_LINUX_CDROM_H
 # include <linux/cdrom.h>
 #endif
@@ -830,6 +834,159 @@
 }
 
 /******************************************************************
+ *		CDROM_ScsiPassThroughDirect
+ *
+ *
+ */
+static DWORD CDROM_ScsiPassThroughDirect(int dev, PSCSI_PASS_THROUGH_DIRECT pPacket)
+{
+    int ret = STATUS_NOT_SUPPORTED;
+#if defined(linux)
+    struct cdrom_generic_command cmd;
+    struct request_sense sense;
+    int io;
+
+    if (pPacket->Length < sizeof(SCSI_PASS_THROUGH_DIRECT))
+	return STATUS_BUFFER_TOO_SMALL;
+
+    if (pPacket->CdbLength > 12)
+        return STATUS_INVALID_PARAMETER;
+
+    if (pPacket->SenseInfoLength > sizeof(sense))
+        return STATUS_INVALID_PARAMETER;
+
+    memset(&cmd, 0, sizeof(cmd));
+    memset(&sense, 0, sizeof(sense));
+
+    memcpy(&(cmd.cmd), &(pPacket->Cdb), pPacket->CdbLength);
+
+    cmd.buffer         = pPacket->DataBuffer;
+    cmd.buflen         = pPacket->DataTransferLength;
+    cmd.sense          = &sense;
+    cmd.quiet          = 0;
+    cmd.timeout        = pPacket->TimeOutValue*HZ;
+
+    switch (pPacket->DataIn)
+    {
+    case SCSI_IOCTL_DATA_OUT:
+        cmd.data_direction = CGC_DATA_WRITE;
+	break;
+    case SCSI_IOCTL_DATA_IN:
+        cmd.data_direction = CGC_DATA_READ;
+	break;
+    case SCSI_IOCTL_DATA_UNSPECIFIED:
+        cmd.data_direction = CGC_DATA_NONE;
+	break;
+    default:
+       return STATUS_INVALID_PARAMETER;
+       break;
+    }
+
+    io = ioctl(dev, CDROM_SEND_PACKET, &cmd);
+
+    if (pPacket->SenseInfoLength != 0)
+    {
+        memcpy((char*)pPacket + pPacket->SenseInfoOffset,
+	       &sense, pPacket->SenseInfoLength);
+    }
+
+    pPacket->ScsiStatus = cmd.stat;
+
+    ret = CDROM_GetStatusCode(io);
+#endif
+    return ret;
+}
+
+/******************************************************************
+ *		CDROM_ScsiPassThrough
+ *
+ *
+ */
+static DWORD CDROM_ScsiPassThrough(int dev, PSCSI_PASS_THROUGH pPacket)
+{
+    int ret = STATUS_NOT_SUPPORTED;
+#if defined(linux)
+    struct cdrom_generic_command cmd;
+    struct request_sense sense;
+    int io;
+
+    if (pPacket->Length < sizeof(SCSI_PASS_THROUGH))
+	return STATUS_BUFFER_TOO_SMALL;
+
+    if (pPacket->CdbLength > 12)
+        return STATUS_INVALID_PARAMETER;
+
+    if (pPacket->SenseInfoLength > sizeof(sense))
+        return STATUS_INVALID_PARAMETER;
+
+    memset(&cmd, 0, sizeof(cmd));
+    memset(&sense, 0, sizeof(sense));
+
+    memcpy(&(cmd.cmd), &(pPacket->Cdb), pPacket->CdbLength);
+
+    if ( pPacket->DataBufferOffset > 0x1000 )
+    {
+        cmd.buffer     = (void*)pPacket->DataBufferOffset;
+    }
+    else
+    {
+        cmd.buffer     = ((void*)pPacket) + pPacket->DataBufferOffset;
+    }
+    cmd.buflen         = pPacket->DataTransferLength;
+    cmd.sense          = &sense;
+    cmd.quiet          = 0;
+    cmd.timeout        = pPacket->TimeOutValue*HZ;
+
+    switch (pPacket->DataIn)
+    {
+    case SCSI_IOCTL_DATA_OUT:
+        cmd.data_direction = CGC_DATA_WRITE;
+	break;
+    case SCSI_IOCTL_DATA_IN:
+        cmd.data_direction = CGC_DATA_READ;
+	break;
+    case SCSI_IOCTL_DATA_UNSPECIFIED:
+        cmd.data_direction = CGC_DATA_NONE;
+	break;
+    default:
+       return STATUS_INVALID_PARAMETER;
+       break;
+    }
+
+    io = ioctl(dev, CDROM_SEND_PACKET, &cmd);
+
+    if (pPacket->SenseInfoLength != 0)
+    {
+        memcpy((char*)pPacket + pPacket->SenseInfoOffset,
+	       &sense, pPacket->SenseInfoLength);
+    }
+
+    pPacket->ScsiStatus = cmd.stat;
+
+    ret = CDROM_GetStatusCode(io);
+#endif
+    return ret;
+}
+
+/******************************************************************
+ *		CDROM_ScsiGetAddress
+ *
+ *
+ */
+static DWORD CDROM_ScsiGetAddress(int dev, PSCSI_ADDRESS addr)
+{
+    FIXME("IOCTL_SCSI_GET_ADDRESS: stub\n");
+
+    addr->Length = sizeof(SCSI_ADDRESS);
+    addr->PortNumber = 0;
+    addr->PathId = 0;
+    addr->TargetId = 1;
+    addr->Lun = 0;
+
+    return 0;
+}
+
+/******************************************************************
  *		CDROM_DeviceIoControl
  *
  *
@@ -892,6 +1049,12 @@
         else error = CDROM_SetTray(dev, TRUE);
         break;
 
+    case IOCTL_CDROM_MEDIA_REMOVAL:
+	FIXME("IOCTL_CDROM_MEDIA_REMOVAL: stub\n");
+        sz = 0;
+	error = 0;
+	break;
+
     case IOCTL_DISK_MEDIA_REMOVAL:
     case IOCTL_STORAGE_MEDIA_REMOVAL:
     case IOCTL_STORAGE_EJECTION_CONTROL:
@@ -1009,6 +1172,26 @@
         else error = CDROM_RawRead(dev, (const RAW_READ_INFO*)lpInBuffer, 
                                    lpOutBuffer, nOutBufferSize, &sz);
         break;
+
+    case IOCTL_SCSI_PASS_THROUGH_DIRECT:
+        sz = sizeof(SCSI_PASS_THROUGH_DIRECT);
+        if (lpOutBuffer == NULL) error = STATUS_INVALID_PARAMETER;
+        else if (nOutBufferSize < sizeof(SCSI_PASS_THROUGH_DIRECT)) error = STATUS_BUFFER_TOO_SMALL;
+        else error = CDROM_ScsiPassThroughDirect(dev, (PSCSI_PASS_THROUGH_DIRECT)lpOutBuffer);
+        break;
+    case IOCTL_SCSI_PASS_THROUGH:
+        sz = sizeof(SCSI_PASS_THROUGH);
+        if (lpOutBuffer == NULL) error = STATUS_INVALID_PARAMETER;
+        else if (nOutBufferSize < sizeof(SCSI_PASS_THROUGH)) error = STATUS_BUFFER_TOO_SMALL;
+        else error = CDROM_ScsiPassThrough(dev, (PSCSI_PASS_THROUGH)lpOutBuffer);
+        break;
+    case IOCTL_SCSI_GET_ADDRESS:
+        sz = 0;
+        if (lpOutBuffer == NULL) error = STATUS_INVALID_PARAMETER;
+        else if (nOutBufferSize < sizeof(SCSI_ADDRESS)) error = STATUS_BUFFER_TOO_SMALL;
+        else error = CDROM_ScsiGetAddress(dev, (PSCSI_ADDRESS)lpOutBuffer);
+        break;
+
     default:
         FIXME("Unsupported IOCTL %lx\n", dwIoControlCode);
         sz = 0;
diff --git a/include/config.h.in b/include/config.h.in
index 5f744ef..4da1baf 100644
--- a/include/config.h.in
+++ b/include/config.h.in
@@ -248,6 +248,9 @@
 /* Define to 1 if you have the <linux/joystick.h> header file. */
 #undef HAVE_LINUX_JOYSTICK_H
 
+/* Define to 1 if you have the <linux/param.h> header file. */
+#undef HAVE_LINUX_PARAM_H
+
 /* Define to 1 if you have the <linux/serial.h> header file. */
 #undef HAVE_LINUX_SERIAL_H
 
diff --git a/include/ntddscsi.h b/include/ntddscsi.h
new file mode 100644
index 0000000..01fd5fc
--- /dev/null
+++ b/include/ntddscsi.h
@@ -0,0 +1,89 @@
+/*
+ * DDK definitions for scsi media access
+ *
+ * Copyright (C) 2002 Laurent Pinchart
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _NTDDSCSI_H_
+#define _NTDDSCSI_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define IOCTL_SCSI_BASE FILE_DEVICE_CONTROLLER
+
+#define IOCTL_SCSI_PASS_THROUGH         CTL_CODE(IOCTL_SCSI_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define IOCTL_SCSI_MINIPORT             CTL_CODE(IOCTL_SCSI_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define IOCTL_SCSI_GET_INQUIRY_DATA     CTL_CODE(IOCTL_SCSI_BASE, 0x0403, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_SCSI_GET_CAPABILITIES     CTL_CODE(IOCTL_SCSI_BASE, 0x0404, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_SCSI_PASS_THROUGH_DIRECT  CTL_CODE(IOCTL_SCSI_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define IOCTL_SCSI_GET_ADDRESS          CTL_CODE(IOCTL_SCSI_BASE, 0x0406, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_SCSI_RESCAN_BUS           CTL_CODE(IOCTL_SCSI_BASE, 0x0407, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_SCSI_GET_DUMP_POINTERS    CTL_CODE(IOCTL_SCSI_BASE, 0x0408, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_SCSI_FREE_DUMP_POINTERS   CTL_CODE(IOCTL_SCSI_BASE, 0x0409, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_IDE_PASS_THROUGH          CTL_CODE(IOCTL_SCSI_BASE, 0x040a, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+
+#define SCSI_IOCTL_DATA_OUT             0
+#define SCSI_IOCTL_DATA_IN              1
+#define SCSI_IOCTL_DATA_UNSPECIFIED     2
+
+typedef struct _SCSI_PASS_THROUGH {
+    USHORT       Length;
+    UCHAR        ScsiStatus;
+    UCHAR        PathId;
+    UCHAR        TargetId;
+    UCHAR        Lun;
+    UCHAR        CdbLength;
+    UCHAR        SenseInfoLength;
+    UCHAR        DataIn;
+    ULONG        DataTransferLength;
+    ULONG        TimeOutValue;
+    ULONG_PTR    DataBufferOffset;
+    ULONG        SenseInfoOffset;
+    UCHAR        Cdb[16];
+} SCSI_PASS_THROUGH, *PSCSI_PASS_THROUGH;
+
+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;
+
+typedef struct _SCSI_ADDRESS {
+    ULONG        Length;
+    UCHAR        PortNumber;
+    UCHAR        PathId;
+    UCHAR        TargetId;
+    UCHAR        Lun;
+} SCSI_ADDRESS, *PSCSI_ADDRESS;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _NTDDSCSI_H_ */