From f012f847a35d91a63e91e157b70758b713afb30c Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Thu, 3 Apr 2008 09:43:38 -0700 Subject: [PATCH] mountmgr.sys: Add scsipassthrough(direct) support in mount manager --- dlls/mountmgr.sys/Makefile.in | 1 + dlls/mountmgr.sys/ioctl.c | 384 +++++++++++++++++++++++++++++++++++++++++ dlls/mountmgr.sys/mountmgr.c | 30 ++++ 3 files changed, 415 insertions(+), 0 deletions(-) create mode 100644 dlls/mountmgr.sys/ioctl.c diff --git a/dlls/mountmgr.sys/Makefile.in b/dlls/mountmgr.sys/Makefile.in index 07f32a7..1d504c8 100644 --- a/dlls/mountmgr.sys/Makefile.in +++ b/dlls/mountmgr.sys/Makefile.in @@ -11,6 +11,7 @@ EXTRALIBS = @DISKARBITRATIONLIB@ -luuid C_SRCS = \ diskarb.c \ hal.c \ + ioctl.c \ mountmgr.c @MAKE_DLL_RULES@ diff --git a/dlls/mountmgr.sys/ioctl.c b/dlls/mountmgr.sys/ioctl.c new file mode 100644 index 0000000..70b625e --- /dev/null +++ b/dlls/mountmgr.sys/ioctl.c @@ -0,0 +1,384 @@ +/* -*- tab-width: 8; c-basic-offset: 4 -*- */ +/* Main file for CD-ROM support + * + * Copyright 1994 Martin Ayotte + * Copyright 1999, 2001, 2003 Eric Pouech + * Copyright 2000 Andreas Mohr + * Copyright 2005 Ivan Leo Puoti + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include "wine/port.h" + +#include +#include +#include +#include +#ifdef HAVE_IO_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif +#include +#ifdef HAVE_SYS_STAT_H +# include +#endif +#include + +#ifdef HAVE_SYS_IOCTL_H +#include +#endif +#ifdef HAVE_SCSI_SG_H +# include +#endif +#ifdef HAVE_SCSI_SCSI_H +# include +# undef REASSIGN_BLOCKS /* avoid conflict with winioctl.h */ +# undef FAILED /* avoid conflict with winerror.h */ +#endif +#ifdef HAVE_SCSI_SCSI_IOCTL_H +# include +#endif +#ifdef HAVE_LINUX_MAJOR_H +# include +#endif +#ifdef HAVE_LINUX_HDREG_H +# include +#endif +#ifdef HAVE_LINUX_PARAM_H +# include +#endif +#ifdef HAVE_LINUX_CDROM_H +# include +#endif +#ifdef HAVE_LINUX_UCDROM_H +# include +#endif +#ifdef HAVE_SYS_CDIO_H +# include +#endif +#ifdef HAVE_SYS_SCSIIO_H +# include +#endif + +#ifdef HAVE_IOKIT_IOKITLIB_H +# include +# include +# include +# include +# include +# define SENSEBUFLEN kSenseDefaultSize +#endif + +#define NONAMELESSUNION +#define NONAMELESSSTRUCT +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winternl.h" +#include "winioctl.h" +#include "ntddstor.h" +#include "ntddcdrm.h" +#include "ddk/ntddcdvd.h" +#include "ntddscsi.h" +#include "wine/server.h" +#include "wine/library.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(cdrom); + + +/*********************************************************************** + * FILE_GetNtStatus(void) + * + * Retrieve the Nt Status code from errno. + * Try to be consistent with FILE_SetDosError(). + */ +static NTSTATUS FILE_GetNtStatus(void) +{ + int err = errno; + + TRACE( "errno = %d\n", errno ); + switch (err) + { + case EAGAIN: return STATUS_SHARING_VIOLATION; + case EBADF: return STATUS_INVALID_HANDLE; + case EBUSY: return STATUS_DEVICE_BUSY; + case ENOSPC: return STATUS_DISK_FULL; + case EPERM: + case EROFS: + case EACCES: return STATUS_ACCESS_DENIED; + case ENOTDIR: return STATUS_OBJECT_PATH_NOT_FOUND; + case ENOENT: return STATUS_OBJECT_NAME_NOT_FOUND; + case EISDIR: return STATUS_FILE_IS_A_DIRECTORY; + case EMFILE: + case ENFILE: return STATUS_TOO_MANY_OPENED_FILES; + case EINVAL: return STATUS_INVALID_PARAMETER; + case ENOTEMPTY: return STATUS_DIRECTORY_NOT_EMPTY; + case EPIPE: return STATUS_PIPE_DISCONNECTED; + case EIO: return STATUS_DEVICE_NOT_READY; +#ifdef ENOMEDIUM + case ENOMEDIUM: return STATUS_NO_MEDIA_IN_DEVICE; +#endif + case ENXIO: return STATUS_NO_SUCH_DEVICE; + case ENOTTY: + case EOPNOTSUPP:return STATUS_NOT_SUPPORTED; + case ECONNRESET:return STATUS_PIPE_DISCONNECTED; + case EFAULT: return STATUS_ACCESS_VIOLATION; + case ESPIPE: return STATUS_ILLEGAL_FUNCTION; + case ENOEXEC: /* ?? */ + case EEXIST: /* ?? */ + default: + FIXME( "Converting errno %d to STATUS_UNSUCCESSFUL\n", err ); + return STATUS_UNSUCCESSFUL; + } +} + +/****************************************************************** + * CDROM_GetStatusCode + * + * + */ +static NTSTATUS CDROM_GetStatusCode(int io) +{ + if (io == 0) return STATUS_SUCCESS; + return FILE_GetNtStatus(); +} + + +/****************************************************************** + * CDROM_ScsiPassThroughDirect + * Implements IOCTL_SCSI_PASS_THROUGH_DIRECT + * + */ +NTSTATUS MOUNTMGR_ScsiPassThroughDirect(int fd, PSCSI_PASS_THROUGH_DIRECT pPacket) +{ + int ret = STATUS_NOT_SUPPORTED; +#ifdef HAVE_SG_IO_HDR_T_INTERFACE_ID + sg_io_hdr_t cmd; + int io; +#elif defined HAVE_SCSIREQ_T_CMD + scsireq_t cmd; + int io; +#endif + DWORD SenseInfoOffset = sizeof(*pPacket); + LPVOID DataBuffer = (char *)pPacket + SenseInfoOffset + pPacket->SenseInfoLength; + +#ifdef HAVE_SG_IO_HDR_T_INTERFACE_ID + RtlZeroMemory(&cmd, sizeof(cmd)); + + cmd.interface_id = 'S'; + cmd.cmd_len = pPacket->CdbLength; + cmd.mx_sb_len = pPacket->SenseInfoLength; + cmd.dxfer_len = pPacket->DataTransferLength; + cmd.dxferp = DataBuffer; + cmd.cmdp = pPacket->Cdb; + cmd.sbp = (unsigned char*)pPacket + SenseInfoOffset; + cmd.timeout = pPacket->TimeOutValue*1000; + + switch (pPacket->DataIn) + { + case SCSI_IOCTL_DATA_IN: + cmd.dxfer_direction = SG_DXFER_FROM_DEV; + break; + case SCSI_IOCTL_DATA_OUT: + cmd.dxfer_direction = SG_DXFER_TO_DEV; + break; + case SCSI_IOCTL_DATA_UNSPECIFIED: + cmd.dxfer_direction = SG_DXFER_NONE; + break; + default: + return STATUS_INVALID_PARAMETER; + } + + io = ioctl(fd, SG_IO, &cmd); + + pPacket->ScsiStatus = cmd.status; + pPacket->DataTransferLength = cmd.resid; + pPacket->SenseInfoLength = cmd.sb_len_wr; + + ret = CDROM_GetStatusCode(io); + +#elif defined HAVE_SCSIREQ_T_CMD + + memset(&cmd, 0, sizeof(cmd)); + memcpy(&(cmd.cmd), &(pPacket->Cdb), pPacket->CdbLength); + + cmd.cmdlen = pPacket->CdbLength; + cmd.databuf = DataBuffer; + cmd.datalen = pPacket->DataTransferLength; + cmd.senselen = pPacket->SenseInfoLength; + cmd.timeout = pPacket->TimeOutValue*1000; /* in milliseconds */ + + switch (pPacket->DataIn) + { + case SCSI_IOCTL_DATA_OUT: + cmd.flags |= SCCMD_WRITE; + break; + case SCSI_IOCTL_DATA_IN: + cmd.flags |= SCCMD_READ; + break; + case SCSI_IOCTL_DATA_UNSPECIFIED: + cmd.flags = 0; + break; + default: + return STATUS_INVALID_PARAMETER; + } + + io = ioctl(fd, SCIOCCOMMAND, &cmd); + + switch (cmd.retsts) + { + case SCCMD_OK: break; + case SCCMD_TIMEOUT: return STATUS_TIMEOUT; + break; + case SCCMD_BUSY: return STATUS_DEVICE_BUSY; + break; + case SCCMD_SENSE: break; + case SCCMD_UNKNOWN: return STATUS_UNSUCCESSFUL; + break; + } + + if (pPacket->SenseInfoLength != 0) + { + memcpy((char*)pPacket + SenseInfoOffset, + cmd.sense, pPacket->SenseInfoLength); + } + + pPacket->ScsiStatus = cmd.status; + + ret = CDROM_GetStatusCode(io); +#endif + return ret; +} + +/****************************************************************** + * CDROM_ScsiPassThrough + * Implements IOCTL_SCSI_PASS_THROUGH + * + */ +NTSTATUS MOUNTMGR_ScsiPassThrough(int fd, PSCSI_PASS_THROUGH pPacket) +{ + int ret = STATUS_NOT_SUPPORTED; +#ifdef HAVE_SG_IO_HDR_T_INTERFACE_ID + sg_io_hdr_t cmd; + int io; +#elif defined HAVE_SCSIREQ_T_CMD + scsireq_t cmd; + int io; +#endif + DWORD SenseInfoOffset = sizeof(*pPacket); + DWORD DataBufferOffset = SenseInfoOffset + pPacket->SenseInfoLength; + +#ifdef HAVE_SG_IO_HDR_T_INTERFACE_ID + RtlZeroMemory(&cmd, sizeof(cmd)); + + cmd.interface_id = 'S'; + cmd.dxfer_len = pPacket->DataTransferLength; + cmd.dxferp = (char*)pPacket + DataBufferOffset; + cmd.cmd_len = pPacket->CdbLength; + cmd.cmdp = pPacket->Cdb; + cmd.mx_sb_len = pPacket->SenseInfoLength; + cmd.timeout = pPacket->TimeOutValue*1000; + + if(cmd.mx_sb_len > 0) + cmd.sbp = (unsigned char*)pPacket + SenseInfoOffset; + + switch (pPacket->DataIn) + { + case SCSI_IOCTL_DATA_IN: + cmd.dxfer_direction = SG_DXFER_FROM_DEV; + break; + case SCSI_IOCTL_DATA_OUT: + cmd.dxfer_direction = SG_DXFER_TO_DEV; + break; + case SCSI_IOCTL_DATA_UNSPECIFIED: + cmd.dxfer_direction = SG_DXFER_NONE; + break; + default: + return STATUS_INVALID_PARAMETER; + } + + io = ioctl(fd, SG_IO, &cmd); + + pPacket->ScsiStatus = cmd.status; + pPacket->DataTransferLength = cmd.resid; + pPacket->SenseInfoLength = cmd.sb_len_wr; + + ret = CDROM_GetStatusCode(io); + +#elif defined HAVE_SCSIREQ_T_CMD + + memset(&cmd, 0, sizeof(cmd)); + memcpy(&(cmd.cmd), &(pPacket->Cdb), pPacket->CdbLength); + + if ( DataBufferOffset > 0x1000 ) + { + cmd.databuf = (void*)DataBufferOffset; + } + else + { + cmd.databuf = (char*)pPacket + DataBufferOffset; + } + + cmd.cmdlen = pPacket->CdbLength; + cmd.datalen = pPacket->DataTransferLength; + cmd.senselen = pPacket->SenseInfoLength; + cmd.timeout = pPacket->TimeOutValue*1000; /* in milliseconds */ + + switch (pPacket->DataIn) + { + case SCSI_IOCTL_DATA_OUT: + cmd.flags |= SCCMD_WRITE; + break; + case SCSI_IOCTL_DATA_IN: + cmd.flags |= SCCMD_READ; + break; + case SCSI_IOCTL_DATA_UNSPECIFIED: + cmd.flags = 0; + break; + default: + return STATUS_INVALID_PARAMETER; + } + + io = ioctl(fd, SCIOCCOMMAND, &cmd); + + switch (cmd.retsts) + { + case SCCMD_OK: break; + case SCCMD_TIMEOUT: return STATUS_TIMEOUT; + break; + case SCCMD_BUSY: return STATUS_DEVICE_BUSY; + break; + case SCCMD_SENSE: break; + case SCCMD_UNKNOWN: return STATUS_UNSUCCESSFUL; + break; + } + + if (pPacket->SenseInfoLength != 0) + { + memcpy((char*)pPacket + SenseInfoOffset, + cmd.sense, pPacket->SenseInfoLength); + } + + pPacket->ScsiStatus = cmd.status; + + ret = CDROM_GetStatusCode(io); +#endif + return ret; +} diff --git a/dlls/mountmgr.sys/mountmgr.c b/dlls/mountmgr.sys/mountmgr.c index 0092069..049cab5 100644 --- a/dlls/mountmgr.sys/mountmgr.c +++ b/dlls/mountmgr.sys/mountmgr.c @@ -43,6 +43,7 @@ #include "ntddstor.h" #include "ntddcdrm.h" +#include "ntddscsi.h" #include "ddk/wdm.h" #include "ddk/mountmgr.h" #include "wine/library.h" @@ -74,6 +75,9 @@ struct mount_point DEVICE_OBJECT *parent; }; +extern NTSTATUS MOUNTMGR_ScsiPassThroughDirect(int fd, PSCSI_PASS_THROUGH_DIRECT pPacket); +extern NTSTATUS MOUNTMGR_ScsiPassThrough(int, PSCSI_PASS_THROUGH pPacket); + static struct mount_point mount_points[MAX_MOUNT_POINTS]; static HKEY mount_key, drive_key; static ULONG globaldevicenumber; @@ -446,6 +450,32 @@ static NTSTATUS WINAPI harddisk_ioctl( DEVICE_OBJECT *device, IRP *irp ) case IOCTL_CDROM_READ_TOC: irp->IoStatus.u.Status = STATUS_INVALID_DEVICE_REQUEST; break; + case IOCTL_SCSI_PASS_THROUGH: + { + int fd = open(disk_info->dev_node, 777); + memcpy(irp->UserBuffer, irp->AssociatedIrp.SystemBuffer, irpsp->Parameters.DeviceIoControl.OutputBufferLength); + if (fd >= 0) + { + irp->IoStatus.u.Status = MOUNTMGR_ScsiPassThrough(fd, irp->UserBuffer); + if (SUCCEEDED(irp->IoStatus.u.Status)) + irp->IoStatus.Information = irpsp->Parameters.DeviceIoControl.OutputBufferLength; + close(fd); + } + } + break; + case IOCTL_SCSI_PASS_THROUGH_DIRECT: + { + int fd = open(disk_info->dev_node, 777); + memcpy(irp->UserBuffer, irp->AssociatedIrp.SystemBuffer, irpsp->Parameters.DeviceIoControl.OutputBufferLength); + if (fd >= 0) + { + irp->IoStatus.u.Status = MOUNTMGR_ScsiPassThroughDirect(fd, irp->UserBuffer); + if (SUCCEEDED(irp->IoStatus.u.Status)) + irp->IoStatus.Information = irpsp->Parameters.DeviceIoControl.OutputBufferLength; + close(fd); + } + } + break; default: FIXME( "unsupported ioctl %x\n", irpsp->Parameters.DeviceIoControl.IoControlCode ); irp->IoStatus.u.Status = STATUS_NOT_SUPPORTED; -- 1.5.4.1