From 6f71fd02bad18daabce3ab100dceb734faf997c8 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 24 Mar 2008 09:09:02 -0700 Subject: [PATCH] ntdll: Do ioctl marshalling for scsipassthrough(direct) --- dlls/ntdll/file.c | 180 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 178 insertions(+), 2 deletions(-) diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c index ce94917..f498d22 100644 --- a/dlls/ntdll/file.c +++ b/dlls/ntdll/file.c @@ -79,6 +79,7 @@ #include "winternl.h" #include "winioctl.h" #include "ddk/ntddser.h" +#include "ntddscsi.h" WINE_DEFAULT_DEBUG_CHANNEL(ntdll); @@ -1222,6 +1223,168 @@ static NTSTATUS server_ioctl_file( HANDLE handle, HANDLE event, } +static NTSTATUS SERVER_ScsiPassThroughDirect(HANDLE handle, HANDLE event, + PIO_APC_ROUTINE apc, PVOID apc_context, + PIO_STATUS_BLOCK io, ULONG code, + char *in_buffer, ULONG in_size, + char *out_buffer, ULONG out_size) +{ + PSCSI_PASS_THROUGH_DIRECT pPacket = (PSCSI_PASS_THROUGH_DIRECT)in_buffer; + PSCSI_PASS_THROUGH_DIRECT sentpacket; + NTSTATUS status; + DWORD size; + + /* Can't put this in the structure, it needs to stay unmodified */ + DWORD SenseInfoOffset, DataBufferOffset; + + if (!in_buffer || !out_buffer) + return STATUS_INVALID_PARAMETER; + + if (in_size < sizeof(SCSI_PASS_THROUGH_DIRECT) || out_size < sizeof(SCSI_PASS_THROUGH_DIRECT)) + return STATUS_BUFFER_TOO_SMALL; + + if (pPacket->Length < sizeof(SCSI_PASS_THROUGH_DIRECT)) + return STATUS_BUFFER_TOO_SMALL; + + if (pPacket->CdbLength > 16) + return STATUS_INVALID_PARAMETER; + + if (pPacket->SenseInfoLength > 48) + return STATUS_INVALID_PARAMETER; + + if (pPacket->DataTransferLength > 0 && !pPacket->DataBuffer) + return STATUS_INVALID_PARAMETER; + + if (pPacket->DataIn != SCSI_IOCTL_DATA_IN && + pPacket->DataIn != SCSI_IOCTL_DATA_OUT && + pPacket->DataIn != SCSI_IOCTL_DATA_UNSPECIFIED) + return STATUS_INVALID_PARAMETER; + + size = sizeof(SCSI_PASS_THROUGH_DIRECT); + size += pPacket->SenseInfoLength; + if (pPacket->DataIn != SCSI_IOCTL_DATA_UNSPECIFIED) + size += pPacket->DataTransferLength; + + in_buffer = RtlAllocateHeap(GetProcessHeap(), 0, size); + sentpacket = (PSCSI_PASS_THROUGH_DIRECT)in_buffer; + if (!in_buffer) + return STATUS_NO_MEMORY; + + memcpy(in_buffer, pPacket, sizeof(SCSI_PASS_THROUGH_DIRECT)); + SenseInfoOffset = sizeof(*pPacket); + DataBufferOffset = SenseInfoOffset + sentpacket->SenseInfoLength; + + /* Append sense data */ + memcpy(in_buffer + SenseInfoOffset, (char*)pPacket + pPacket->SenseInfoOffset, pPacket->SenseInfoLength); + + /* Append memory */ + if (pPacket->DataIn == SCSI_IOCTL_DATA_OUT) + { + memcpy(in_buffer + DataBufferOffset, pPacket->DataBuffer, pPacket->DataTransferLength); + } + + /* Do ioctl, except locally */ + status = server_ioctl_file( handle, event, apc, apc_context, io, code, + in_buffer, size, in_buffer, size ); + + if (FAILED(status)) + { + WARN("Failed with result %08x\n", status); + goto out; + } + if (pPacket->DataIn == SCSI_IOCTL_DATA_IN) + { + memcpy(pPacket->DataBuffer, in_buffer + DataBufferOffset, sentpacket->DataTransferLength); + } + + memcpy((char *)pPacket + pPacket->SenseInfoOffset, in_buffer + SenseInfoOffset, sentpacket->SenseInfoLength); + memcpy(out_buffer, sentpacket, sizeof(SCSI_PASS_THROUGH_DIRECT)); + +out: + RtlFreeHeap(GetProcessHeap(), 0, in_buffer); + return status; +} + +static NTSTATUS SERVER_ScsiPassThrough(HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, PVOID apc_context, PIO_STATUS_BLOCK io, + ULONG code, char *in_buffer, ULONG in_size, char *out_buffer, ULONG out_size) +{ + PSCSI_PASS_THROUGH pPacket = (PSCSI_PASS_THROUGH)in_buffer; + PSCSI_PASS_THROUGH sentpacket; + NTSTATUS status; + DWORD size; + + /* Can't put this in the structure, it needs to stay unmodified */ + DWORD SenseInfoOffset, DataBufferOffset; + + if (!in_buffer || !out_buffer) + return STATUS_INVALID_PARAMETER; + + if (in_size < sizeof(SCSI_PASS_THROUGH) || out_size < sizeof(SCSI_PASS_THROUGH)) + return STATUS_BUFFER_TOO_SMALL; + + if (pPacket->Length < sizeof(SCSI_PASS_THROUGH)) + return STATUS_BUFFER_TOO_SMALL; + + if (pPacket->CdbLength > 16) + return STATUS_INVALID_PARAMETER; + + if (pPacket->SenseInfoLength > 48) + return STATUS_INVALID_PARAMETER; + + if (pPacket->DataTransferLength > 0 && !pPacket->DataBufferOffset) + return STATUS_INVALID_PARAMETER; + + if (pPacket->DataIn != SCSI_IOCTL_DATA_IN && + pPacket->DataIn != SCSI_IOCTL_DATA_OUT && + pPacket->DataIn != SCSI_IOCTL_DATA_UNSPECIFIED) + return STATUS_INVALID_PARAMETER; + + size = sizeof(SCSI_PASS_THROUGH); + size += pPacket->SenseInfoLength; + if (pPacket->DataIn != SCSI_IOCTL_DATA_UNSPECIFIED) + size += pPacket->DataTransferLength; + + in_buffer = RtlAllocateHeap(GetProcessHeap(), 0, size); + sentpacket = (PSCSI_PASS_THROUGH)in_buffer; + if (!in_buffer) + return STATUS_NO_MEMORY; + + memcpy(in_buffer, pPacket, sizeof(SCSI_PASS_THROUGH)); + SenseInfoOffset = sizeof(*pPacket); + DataBufferOffset = SenseInfoOffset + sentpacket->SenseInfoLength; + + /* Append sense data */ + memcpy(in_buffer + SenseInfoOffset, (char*)pPacket + pPacket->SenseInfoOffset, pPacket->SenseInfoLength); + + /* Append memory */ + if (pPacket->DataIn == SCSI_IOCTL_DATA_OUT) + { + memcpy(in_buffer + DataBufferOffset, (char *)pPacket + pPacket->DataBufferOffset, pPacket->DataTransferLength); + } + + /* Do ioctl, except locally */ + status = server_ioctl_file( handle, event, apc, apc_context, io, code, + in_buffer, size, in_buffer, size ); + + if (FAILED(status)) + { + WARN("Failed with result %08x\n", status); + goto out; + } + if (pPacket->DataIn == SCSI_IOCTL_DATA_IN) + { + memcpy((char *)pPacket + pPacket->DataBufferOffset, in_buffer + DataBufferOffset, sentpacket->DataTransferLength); + } + + memcpy((char *)pPacket + pPacket->SenseInfoOffset, in_buffer + SenseInfoOffset, sentpacket->SenseInfoLength); + memcpy(out_buffer, sentpacket, sizeof(SCSI_PASS_THROUGH)); + +out: + RtlFreeHeap(GetProcessHeap(), 0, in_buffer); + return status; +} + + /************************************************************************** * NtDeviceIoControlFile [NTDLL.@] * ZwDeviceIoControlFile [NTDLL.@] @@ -1278,8 +1441,21 @@ NTSTATUS WINAPI NtDeviceIoControlFile(HANDLE handle, HANDLE event, } if (status == STATUS_NOT_SUPPORTED || status == STATUS_BAD_DEVICE_TYPE) - status = server_ioctl_file( handle, event, apc, apc_context, io, code, - in_buffer, in_size, out_buffer, out_size ); + { + if (code == IOCTL_SCSI_PASS_THROUGH_DIRECT) + { + status = SERVER_ScsiPassThroughDirect( handle, event, apc, apc_context, io, code, + in_buffer, in_size, out_buffer, out_size ); + } + else if (code == IOCTL_SCSI_PASS_THROUGH) + { + status = SERVER_ScsiPassThrough( handle, event, apc, apc_context, io, code, + in_buffer, in_size, out_buffer, out_size ); + } + else + status = server_ioctl_file( handle, event, apc, apc_context, io, code, + in_buffer, in_size, out_buffer, out_size ); + } if (status != STATUS_PENDING) io->u.Status = status; return status; -- 1.5.4.1