This is intended to replace !8120. Once this MR is approved, I'll submit the `IOCTL_SCSI_PASS_THROUGH_DIRECT` patch as part two.
From: Akihiro Sagawa sagawa.aki@gmail.com
Due to insufficient testing, HAVE_SCSIREQ_T_CMD was never defined and the issue remained unnoticed for over two decades. It is better to remove the blocks than to maintain them. --- configure | 12 ----- configure.ac | 4 +- dlls/ntdll/unix/cdrom.c | 114 ---------------------------------------- include/config.h.in | 3 -- 4 files changed, 2 insertions(+), 131 deletions(-)
diff --git a/configure b/configure index 750e43fb7e4..7ff3d4040a2 100755 --- a/configure +++ b/configure @@ -21558,18 +21558,6 @@ printf "%s\n" "#define HAVE_STRUCT_SOCKADDR_UN_SUN_LEN 1" >>confdefs.h fi
-ac_fn_c_check_member "$LINENO" "scsireq_t" "cmd" "ac_cv_member_scsireq_t_cmd" "#include <sys/types.h> -#ifdef HAVE_SCSI_SG_H -#include <scsi/sg.h> -#endif -" -if test "x$ac_cv_member_scsireq_t_cmd" = xyes -then : - -printf "%s\n" "#define HAVE_SCSIREQ_T_CMD 1" >>confdefs.h - - -fi ac_fn_c_check_member "$LINENO" "sg_io_hdr_t" "interface_id" "ac_cv_member_sg_io_hdr_t_interface_id" "#include <sys/types.h> #ifdef HAVE_SCSI_SG_H #include <scsi/sg.h> diff --git a/configure.ac b/configure.ac index 7481d175840..94e18f9faa1 100644 --- a/configure.ac +++ b/configure.ac @@ -2193,8 +2193,8 @@ AC_CHECK_MEMBERS([struct sockaddr_un.sun_len],,, # include <sys/un.h> #endif])
-dnl Check for scsireq_t and sg_io_hdr_t members -AC_CHECK_MEMBERS([scsireq_t.cmd, sg_io_hdr_t.interface_id],,, +dnl Check for sg_io_hdr_t members +AC_CHECK_MEMBERS([sg_io_hdr_t.interface_id],,, [#include <sys/types.h> #ifdef HAVE_SCSI_SG_H #include <scsi/sg.h> diff --git a/dlls/ntdll/unix/cdrom.c b/dlls/ntdll/unix/cdrom.c index af98aabb9f2..f4f11c8e62f 100644 --- a/dlls/ntdll/unix/cdrom.c +++ b/dlls/ntdll/unix/cdrom.c @@ -1617,9 +1617,6 @@ static NTSTATUS CDROM_ScsiPassThroughDirect(int fd, PSCSI_PASS_THROUGH_DIRECT pP #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; #elif defined __APPLE__ dk_scsi_command_t cmd; int io; @@ -1677,56 +1674,6 @@ static NTSTATUS CDROM_ScsiPassThroughDirect(int fd, PSCSI_PASS_THROUGH_DIRECT pP
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 = pPacket->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 + pPacket->SenseInfoOffset, - cmd.sense, pPacket->SenseInfoLength); - } - - pPacket->ScsiStatus = cmd.status; - - ret = CDROM_GetStatusCode(io); - #elif defined(__APPLE__)
memset(&cmd, 0, sizeof(cmd)); @@ -1799,9 +1746,6 @@ static NTSTATUS CDROM_ScsiPassThrough(int fd, PSCSI_PASS_THROUGH pPacket) #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; #elif defined __APPLE__ dk_scsi_command_t cmd; int io; @@ -1861,64 +1805,6 @@ static NTSTATUS CDROM_ScsiPassThrough(int fd, PSCSI_PASS_THROUGH pPacket)
ret = CDROM_GetStatusCode(io);
-#elif defined HAVE_SCSIREQ_T_CMD - - memset(&cmd, 0, sizeof(cmd)); - memcpy(&(cmd.cmd), &(pPacket->Cdb), pPacket->CdbLength); - - if ( pPacket->DataBufferOffset > 0x1000 ) - { - cmd.databuf = (void*)pPacket->DataBufferOffset; - } - else - { - cmd.databuf = (char*)pPacket + 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 + pPacket->SenseInfoOffset, - cmd.sense, pPacket->SenseInfoLength); - } - - pPacket->ScsiStatus = cmd.status; - - ret = CDROM_GetStatusCode(io); - #elif defined(__APPLE__)
memset(&cmd, 0, sizeof(cmd)); diff --git a/include/config.h.in b/include/config.h.in index d002246e719..84e71120248 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -375,9 +375,6 @@ /* Define to 1 if you have the 'sched_yield' function. */ #undef HAVE_SCHED_YIELD
-/* Define to 1 if 'cmd' is a member of 'scsireq_t'. */ -#undef HAVE_SCSIREQ_T_CMD - /* Define to 1 if you have the <scsi/scsi.h> header file. */ #undef HAVE_SCSI_SCSI_H
From: Akihiro Sagawa sagawa.aki@gmail.com
This reverts most of commit b8b15f3e6e0e. Since its introduction in Linux 2.2.16, request_sense in linux/cdrom.h has been a structure, not a type. Therefore, HAVE_REQUEST_SENSE has not been defined for over two decades. --- configure | 11 ----------- configure.ac | 2 -- dlls/ntdll/unix/cdrom.c | 6 ------ include/config.h.in | 3 --- 4 files changed, 22 deletions(-)
diff --git a/configure b/configure index 7ff3d4040a2..e6868a98b9c 100755 --- a/configure +++ b/configure @@ -21481,17 +21481,6 @@ printf "%s\n" "#define HAVE_SCHED_SETAFFINITY 1" >>confdefs.h fi
-ac_fn_c_check_type "$LINENO" "request_sense" "ac_cv_type_request_sense" "#include <linux/cdrom.h> -" -if test "x$ac_cv_type_request_sense" = xyes -then : - -printf "%s\n" "#define HAVE_REQUEST_SENSE 1" >>confdefs.h - - -fi - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we can use re-entrant gethostbyname_r Linux style" >&5 printf %s "checking whether we can use re-entrant gethostbyname_r Linux style... " >&6; } if test ${wine_cv_linux_gethostbyname_r_6+y} diff --git a/configure.ac b/configure.ac index 94e18f9faa1..0ab295b0f52 100644 --- a/configure.ac +++ b/configure.ac @@ -2160,8 +2160,6 @@ fi
dnl **** Check for types ****
-AC_CHECK_TYPES([request_sense],,,[#include <linux/cdrom.h>]) - AC_CACHE_CHECK([whether we can use re-entrant gethostbyname_r Linux style], wine_cv_linux_gethostbyname_r_6, AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <netdb.h>]],[[ diff --git a/dlls/ntdll/unix/cdrom.c b/dlls/ntdll/unix/cdrom.c index f4f11c8e62f..53bf2e1b552 100644 --- a/dlls/ntdll/unix/cdrom.c +++ b/dlls/ntdll/unix/cdrom.c @@ -1631,9 +1631,6 @@ static NTSTATUS CDROM_ScsiPassThroughDirect(int fd, PSCSI_PASS_THROUGH_DIRECT pP #ifdef SENSEBUFLEN if (pPacket->SenseInfoLength > SENSEBUFLEN) return STATUS_INVALID_PARAMETER; -#elif defined HAVE_REQUEST_SENSE - if (pPacket->SenseInfoLength > sizeof(struct request_sense)) - return STATUS_INVALID_PARAMETER; #endif
if (pPacket->DataTransferLength > 0 && !pPacket->DataBuffer) @@ -1760,9 +1757,6 @@ static NTSTATUS CDROM_ScsiPassThrough(int fd, PSCSI_PASS_THROUGH pPacket) #ifdef SENSEBUFLEN if (pPacket->SenseInfoLength > SENSEBUFLEN) return STATUS_INVALID_PARAMETER; -#elif defined HAVE_REQUEST_SENSE - if (pPacket->SenseInfoLength > sizeof(struct request_sense)) - return STATUS_INVALID_PARAMETER; #endif
if (pPacket->DataTransferLength > 0 && pPacket->DataBufferOffset < sizeof(SCSI_PASS_THROUGH)) diff --git a/include/config.h.in b/include/config.h.in index 84e71120248..b3d9777d1f4 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -351,9 +351,6 @@ /* Define to 1 if you have the <pwd.h> header file. */ #undef HAVE_PWD_H
-/* Define to 1 if the system has the type 'request_sense'. */ -#undef HAVE_REQUEST_SENSE - /* Define if you have the resolver library and header */ #undef HAVE_RESOLV
From: Akihiro Sagawa sagawa.aki@gmail.com
--- dlls/ntdll/unix/cdrom.c | 78 +++++++++++++++++++++++++---------------- 1 file changed, 48 insertions(+), 30 deletions(-)
diff --git a/dlls/ntdll/unix/cdrom.c b/dlls/ntdll/unix/cdrom.c index 53bf2e1b552..68b9b5e5b06 100644 --- a/dlls/ntdll/unix/cdrom.c +++ b/dlls/ntdll/unix/cdrom.c @@ -1737,7 +1737,7 @@ static NTSTATUS CDROM_ScsiPassThroughDirect(int fd, PSCSI_PASS_THROUGH_DIRECT pP * Implements IOCTL_SCSI_PASS_THROUGH * */ -static NTSTATUS CDROM_ScsiPassThrough(int fd, PSCSI_PASS_THROUGH pPacket) +static NTSTATUS CDROM_ScsiPassThrough(int fd, const SCSI_PASS_THROUGH *in_pkt, SCSI_PASS_THROUGH *out_pkt) { int ret = STATUS_NOT_SUPPORTED; #ifdef HAVE_SG_IO_HDR_T_INTERFACE_ID @@ -1748,75 +1748,77 @@ static NTSTATUS CDROM_ScsiPassThrough(int fd, PSCSI_PASS_THROUGH pPacket) int io; #endif
- if (pPacket->Length < sizeof(SCSI_PASS_THROUGH)) + if (in_pkt->Length < sizeof(SCSI_PASS_THROUGH)) return STATUS_BUFFER_TOO_SMALL;
- if (pPacket->CdbLength > 16) + if (in_pkt->CdbLength > 16) return STATUS_INVALID_PARAMETER;
#ifdef SENSEBUFLEN - if (pPacket->SenseInfoLength > SENSEBUFLEN) + if (in_pkt->SenseInfoLength > SENSEBUFLEN) return STATUS_INVALID_PARAMETER; #endif
- if (pPacket->DataTransferLength > 0 && pPacket->DataBufferOffset < sizeof(SCSI_PASS_THROUGH)) + if (in_pkt->DataTransferLength > 0 && in_pkt->DataBufferOffset < sizeof(SCSI_PASS_THROUGH)) return STATUS_INVALID_PARAMETER;
#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 + pPacket->DataBufferOffset; - cmd.cmd_len = pPacket->CdbLength; - cmd.cmdp = pPacket->Cdb; - cmd.mx_sb_len = pPacket->SenseInfoLength; - cmd.timeout = pPacket->TimeOutValue*1000; + cmd.dxfer_len = in_pkt->DataTransferLength; + cmd.cmd_len = in_pkt->CdbLength; + cmd.cmdp = (unsigned char*)in_pkt->Cdb; + cmd.mx_sb_len = in_pkt->SenseInfoLength; + cmd.timeout = in_pkt->TimeOutValue*1000;
if(cmd.mx_sb_len > 0) - cmd.sbp = (unsigned char*)pPacket + pPacket->SenseInfoOffset; + cmd.sbp = (unsigned char*)out_pkt + in_pkt->SenseInfoOffset;
- switch (pPacket->DataIn) + switch (in_pkt->DataIn) { case SCSI_IOCTL_DATA_IN: + cmd.dxferp = (char*)out_pkt + in_pkt->DataBufferOffset; cmd.dxfer_direction = SG_DXFER_FROM_DEV; - break; + break; case SCSI_IOCTL_DATA_OUT: + cmd.dxferp = (char*)in_pkt + in_pkt->DataBufferOffset; cmd.dxfer_direction = SG_DXFER_TO_DEV; - break; + break; case SCSI_IOCTL_DATA_UNSPECIFIED: cmd.dxfer_direction = SG_DXFER_NONE; - break; + 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; + out_pkt->ScsiStatus = cmd.status; + out_pkt->DataTransferLength = in_pkt->DataTransferLength - cmd.resid; + out_pkt->SenseInfoLength = cmd.sb_len_wr;
ret = CDROM_GetStatusCode(io);
#elif defined(__APPLE__)
memset(&cmd, 0, sizeof(cmd)); - memcpy(cmd.cdb, pPacket->Cdb, pPacket->CdbLength); + memcpy(cmd.cdb, in_pkt->Cdb, in_pkt->CdbLength);
- cmd.cdbSize = pPacket->CdbLength; - cmd.buffer = (char*)pPacket + pPacket->DataBufferOffset; - cmd.bufferSize = pPacket->DataTransferLength; - cmd.sense = (char*)pPacket + pPacket->SenseInfoOffset; - cmd.senseLen = pPacket->SenseInfoLength; - cmd.timeout = pPacket->TimeOutValue*1000; /* in milliseconds */ + cmd.cdbSize = in_pkt->CdbLength; + cmd.bufferSize = in_pkt->DataTransferLength; + cmd.sense = (char*)out_pkt + in_pkt->SenseInfoOffset; + cmd.senseLen = in_pkt->SenseInfoLength; + cmd.timeout = in_pkt->TimeOutValue*1000; /* in milliseconds */
- switch (pPacket->DataIn) + switch (in_pkt->DataIn) { case SCSI_IOCTL_DATA_OUT: + cmd.buffer = (char*)in_pkt + in_pkt->DataBufferOffset; cmd.direction = kSCSIDataTransfer_FromInitiatorToTarget; break; case SCSI_IOCTL_DATA_IN: + cmd.buffer = (char*)out_pkt + in_pkt->DataBufferOffset; cmd.direction = kSCSIDataTransfer_FromTargetToInitiator; break; case SCSI_IOCTL_DATA_UNSPECIFIED: @@ -1856,10 +1858,26 @@ static NTSTATUS CDROM_ScsiPassThrough(int fd, PSCSI_PASS_THROUGH pPacket) }
if (cmd.status != kSCSITaskStatus_No_Status) - pPacket->ScsiStatus = cmd.status; + out_pkt->ScsiStatus = cmd.status;
ret = CDROM_GetStatusCode(io); + + /* FIXME: Update DataTransferLength and SenseInfoLength */ #endif + if (ret == STATUS_SUCCESS) + { + out_pkt->Length = sizeof(*out_pkt); + if (out_pkt != in_pkt) + { + out_pkt->CdbLength = in_pkt->CdbLength; + out_pkt->DataIn = in_pkt->DataIn; + out_pkt->TimeOutValue = in_pkt->TimeOutValue; + out_pkt->DataBufferOffset = in_pkt->DataBufferOffset; + out_pkt->SenseInfoOffset = in_pkt->SenseInfoOffset; + memcpy(out_pkt->Cdb, in_pkt->Cdb, sizeof(in_pkt->Cdb)); + } + } + return ret; }
@@ -2938,9 +2956,9 @@ NTSTATUS cdrom_DeviceIoControl( HANDLE device, HANDLE event, PIO_APC_ROUTINE apc break; case IOCTL_SCSI_PASS_THROUGH: sz = sizeof(SCSI_PASS_THROUGH); - if (out_buffer == NULL) status = STATUS_INVALID_PARAMETER; + if (in_buffer == NULL || out_buffer == NULL) status = STATUS_INVALID_PARAMETER; else if (out_size < sizeof(SCSI_PASS_THROUGH)) status = STATUS_BUFFER_TOO_SMALL; - else status = CDROM_ScsiPassThrough(fd, out_buffer); + else status = CDROM_ScsiPassThrough(fd, in_buffer, out_buffer); break; case IOCTL_SCSI_GET_CAPABILITIES: sz = sizeof(IO_SCSI_CAPABILITIES);
From: Akihiro Sagawa sagawa.aki@gmail.com
--- dlls/ntdll/unix/cdrom.c | 98 +++++++++++++++++++++++++++++++++++++++-- include/ntddscsi.h | 16 +++++++ 2 files changed, 110 insertions(+), 4 deletions(-)
diff --git a/dlls/ntdll/unix/cdrom.c b/dlls/ntdll/unix/cdrom.c index 68b9b5e5b06..b2603316fcc 100644 --- a/dlls/ntdll/unix/cdrom.c +++ b/dlls/ntdll/unix/cdrom.c @@ -1881,6 +1881,86 @@ static NTSTATUS CDROM_ScsiPassThrough(int fd, const SCSI_PASS_THROUGH *in_pkt, S return ret; }
+static NTSTATUS CDROM_ScsiPassThrough32(int fd, const SCSI_PASS_THROUGH32 *in_pkt32, SCSI_PASS_THROUGH32 *out_pkt32) +{ + SCSI_PASS_THROUGH *pkt; + ULONG_PTR ptr; + NTSTATUS ret; + + if (in_pkt32->Length < sizeof(SCSI_PASS_THROUGH32)) + return STATUS_BUFFER_TOO_SMALL; + + if (in_pkt32->CdbLength > sizeof(in_pkt32->Cdb)) + return STATUS_INVALID_PARAMETER; + + if (in_pkt32->DataTransferLength > 0) + { + if (in_pkt32->DataBufferOffset < sizeof(SCSI_PASS_THROUGH32)) + return STATUS_INVALID_PARAMETER; + ptr = (ULONG_PTR)in_pkt32 + in_pkt32->DataBufferOffset; + if (ptr < (ULONG_PTR)in_pkt32) + return STATUS_INVALID_PARAMETER; + if ((ptr + in_pkt32->DataTransferLength) < ptr) + return STATUS_INVALID_PARAMETER; + } + + if (in_pkt32->SenseInfoLength > 0) + { + if (in_pkt32->SenseInfoOffset < sizeof(SCSI_PASS_THROUGH32)) + return STATUS_INVALID_PARAMETER; + ptr = (ULONG_PTR)in_pkt32 + in_pkt32->SenseInfoOffset; + if (ptr < (ULONG_PTR)in_pkt32) + return STATUS_INVALID_PARAMETER; + if ((ptr + in_pkt32->SenseInfoLength) < ptr) + return STATUS_INVALID_PARAMETER; + } + + pkt = calloc(1, sizeof(SCSI_PASS_THROUGH) + in_pkt32->SenseInfoLength + in_pkt32->DataTransferLength); + if (!pkt) return STATUS_NO_MEMORY; + + pkt->Length = sizeof(SCSI_PASS_THROUGH); + pkt->CdbLength = in_pkt32->CdbLength; + pkt->SenseInfoLength = in_pkt32->SenseInfoLength; + pkt->DataIn = in_pkt32->DataIn; + pkt->DataTransferLength = in_pkt32->DataTransferLength; + pkt->TimeOutValue = in_pkt32->TimeOutValue; + pkt->DataBufferOffset = sizeof(SCSI_PASS_THROUGH) + in_pkt32->SenseInfoLength; + pkt->SenseInfoOffset = sizeof(SCSI_PASS_THROUGH); + memcpy(pkt->Cdb, in_pkt32->Cdb, sizeof(pkt->Cdb)); + if (pkt->DataIn == SCSI_IOCTL_DATA_OUT) + memcpy((char*)pkt + pkt->DataBufferOffset, + (const char*)in_pkt32 + in_pkt32->DataBufferOffset, + in_pkt32->DataTransferLength); + + ret = CDROM_ScsiPassThrough(fd, pkt, pkt); + if (NT_ERROR(ret)) goto done; + + out_pkt32->Length = sizeof(SCSI_PASS_THROUGH32); + out_pkt32->ScsiStatus = pkt->ScsiStatus; + out_pkt32->PathId = pkt->PathId; + out_pkt32->TargetId = pkt->TargetId; + out_pkt32->Lun = pkt->Lun; + out_pkt32->CdbLength = pkt->CdbLength; + out_pkt32->SenseInfoLength = pkt->SenseInfoLength; + out_pkt32->DataIn = pkt->DataIn; + out_pkt32->DataTransferLength = pkt->DataTransferLength; + out_pkt32->TimeOutValue = pkt->TimeOutValue; + out_pkt32->DataBufferOffset = in_pkt32->DataBufferOffset; + out_pkt32->SenseInfoOffset = in_pkt32->SenseInfoOffset; + memcpy(out_pkt32->Cdb, pkt->Cdb, sizeof(out_pkt32->Cdb)); + memcpy((char*)out_pkt32 + out_pkt32->SenseInfoOffset, + (const char*)pkt + pkt->SenseInfoOffset, + pkt->SenseInfoLength); + if (pkt->DataIn == SCSI_IOCTL_DATA_IN) + memcpy((char*)out_pkt32 + out_pkt32->DataBufferOffset, + (const char*)pkt + pkt->DataBufferOffset, + pkt->DataTransferLength); + +done: + free(pkt); + return ret; +} + /****************************************************************** * CDROM_ScsiGetCaps * @@ -2955,10 +3035,20 @@ NTSTATUS cdrom_DeviceIoControl( HANDLE device, HANDLE event, PIO_APC_ROUTINE apc else status = CDROM_ScsiPassThroughDirect(fd, out_buffer); break; case IOCTL_SCSI_PASS_THROUGH: - sz = sizeof(SCSI_PASS_THROUGH); - if (in_buffer == NULL || out_buffer == NULL) status = STATUS_INVALID_PARAMETER; - else if (out_size < sizeof(SCSI_PASS_THROUGH)) status = STATUS_BUFFER_TOO_SMALL; - else status = CDROM_ScsiPassThrough(fd, in_buffer, out_buffer); + if (in_wow64_call()) + { + sz = sizeof(SCSI_PASS_THROUGH32); + if (in_buffer == NULL || out_buffer == NULL) status = STATUS_INVALID_PARAMETER; + else if (out_size < sizeof(SCSI_PASS_THROUGH32)) status = STATUS_BUFFER_TOO_SMALL; + else status = CDROM_ScsiPassThrough32(fd, in_buffer, out_buffer); + } + else + { + sz = sizeof(SCSI_PASS_THROUGH); + if (in_buffer == NULL || out_buffer == NULL) status = STATUS_INVALID_PARAMETER; + else if (out_size < sizeof(SCSI_PASS_THROUGH)) status = STATUS_BUFFER_TOO_SMALL; + else status = CDROM_ScsiPassThrough(fd, in_buffer, out_buffer); + } break; case IOCTL_SCSI_GET_CAPABILITIES: sz = sizeof(IO_SCSI_CAPABILITIES); diff --git a/include/ntddscsi.h b/include/ntddscsi.h index 390b653efb8..b42cb4e4a82 100644 --- a/include/ntddscsi.h +++ b/include/ntddscsi.h @@ -77,6 +77,22 @@ typedef struct _SCSI_PASS_THROUGH_DIRECT { UCHAR Cdb[16]; } SCSI_PASS_THROUGH_DIRECT, *PSCSI_PASS_THROUGH_DIRECT;
+typedef struct _SCSI_PASS_THROUGH32 { + USHORT Length; + UCHAR ScsiStatus; + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; + UCHAR CdbLength; + UCHAR SenseInfoLength; + UCHAR DataIn; + ULONG DataTransferLength; + ULONG TimeOutValue; + ULONG DataBufferOffset; + ULONG SenseInfoOffset; + UCHAR Cdb[16]; +} SCSI_PASS_THROUGH32, *PSCSI_PASS_THROUGH32; + typedef struct _SCSI_ADDRESS { ULONG Length; UCHAR PortNumber;
From: Akihiro Sagawa sagawa.aki@gmail.com
--- dlls/kernel32/tests/volume.c | 171 +++++++++++++++++++++++++++++++++++ 1 file changed, 171 insertions(+)
diff --git a/dlls/kernel32/tests/volume.c b/dlls/kernel32/tests/volume.c index aa403abf52d..6de12add2c6 100644 --- a/dlls/kernel32/tests/volume.c +++ b/dlls/kernel32/tests/volume.c @@ -24,6 +24,7 @@ #include "windef.h" #include "winbase.h" #include "winioctl.h" +#include "ntddscsi.h" #include "ntddstor.h" #include "winternl.h" #include "ddk/ntddcdvd.h" @@ -62,6 +63,27 @@ static BOOL (WINAPI *pCreateSymbolicLinkA)(const char *, const char *, DWORD); static BOOL (WINAPI *pGetVolumeInformationByHandleW)(HANDLE, WCHAR *, DWORD, DWORD *, DWORD *, DWORD *, WCHAR *, DWORD); static HRESULT (WINAPI *pGetDiskSpaceInformationA)(LPCSTR, DISK_SPACE_INFORMATION *);
+#define READ_ONLY_DIRECT_ACCESS_DEVICE 0x05 +#define SCSISTAT_GOOD 0x00 +#define SCSISTAT_CHECK_CONDITION 0x02 +#define SCSI_SENSE_NOT_READY 0x02 +#define SCSI_SENSE_ILLEGAL_REQUEST 0x05 + +static const unsigned char inquiry_cmd[6] = { + /* INQUIRY Command */ + [0] = 0x12, + /* Allocation Length */ + [3] = 0, 36, +}; +static const unsigned char read_cmd[10] = { + /* READ (10) Command */ + [0] = 0x28, + /* Starting Logical Block Address */ + [2] = 0xde, 0xad, 0xbe, 0xef, + /* Transfer Length */ + [7] = 0, 1, +}; + /* ############################### */
static void test_query_dos_deviceA(void) @@ -1266,6 +1288,143 @@ static void test_dvd_read_structure(HANDLE handle) ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "IOCTL_DVD_READ_STRUCTURE should have failed %d %lu\n", ret, GetLastError()); }
+static void test_scsi_pass_through(HANDLE device) +{ + struct scsi_pass_through_buffer { + SCSI_PASS_THROUGH packet; + UCHAR sense[32]; + UCHAR data[2048]; + } buf; + SCSI_PASS_THROUGH packet; + UCHAR sense_key; + DWORD size; + BOOL ret; + + /* Test INQUIRY with different I/O buffer */ + memset(&packet, 0, sizeof(packet)); + packet.Length = sizeof(SCSI_PASS_THROUGH); + packet.CdbLength = sizeof(inquiry_cmd); + packet.DataIn = SCSI_IOCTL_DATA_IN; + packet.DataTransferLength = inquiry_cmd[4]; + packet.SenseInfoLength = 0; + packet.TimeOutValue = 2; + packet.DataBufferOffset = offsetof(struct scsi_pass_through_buffer, data); + packet.SenseInfoOffset = 0; + memcpy(packet.Cdb, inquiry_cmd, sizeof(inquiry_cmd)); + + memset(&buf, 0xcc, sizeof(buf)); + size = 0xdeadbeef; + ret = DeviceIoControl(device, IOCTL_SCSI_PASS_THROUGH, + &packet, sizeof(packet), &buf, sizeof(buf), &size, NULL); + ok(ret, "DeviceIoControl failed, last=%ld\n", GetLastError()); + + trace("size %lu, sense %lu+%u, data %lu+%lu\n", + size, buf.packet.SenseInfoOffset, buf.packet.SenseInfoLength, + (DWORD)buf.packet.DataBufferOffset, buf.packet.DataTransferLength); + todo_wine ok(size == (DWORD)buf.packet.DataBufferOffset + buf.packet.DataTransferLength, "unexpected size %lu\n", size); + + ok((buf.data[0] & 0x1f) == READ_ONLY_DIRECT_ACCESS_DEVICE, "unexpected device type %d\n", buf.data[0] & 0x1f); + ok(buf.packet.Length == sizeof(SCSI_PASS_THROUGH), "got Length %u\n", buf.packet.Length); + ok(buf.packet.ScsiStatus == SCSISTAT_GOOD, "got ScsiStatus %u\n", buf.packet.ScsiStatus); + ok(buf.packet.CdbLength == sizeof(inquiry_cmd), "got CdbLength %u\n", buf.packet.CdbLength); + ok(buf.packet.DataIn == SCSI_IOCTL_DATA_IN, "got DataIn %u\n", buf.packet.DataIn); + ok(buf.packet.DataTransferLength == packet.Cdb[4], "got DataTransferLength %lu\n", buf.packet.DataTransferLength); + ok(!buf.packet.SenseInfoLength, "got SenseInfoLength %u\n", buf.packet.SenseInfoLength); + ok(buf.packet.TimeOutValue == packet.TimeOutValue, "got TimeOutValue %lu\n", buf.packet.TimeOutValue); + ok(buf.packet.DataBufferOffset == packet.DataBufferOffset, "got DataBufferOffset %lu\n", (DWORD)buf.packet.DataBufferOffset); + ok(buf.packet.SenseInfoOffset == packet.SenseInfoOffset, "got SenseInfoOffset %lu\n", buf.packet.SenseInfoOffset); + ok(!memcmp(buf.packet.Cdb, packet.Cdb, sizeof(packet.Cdb)), "got unexpected Cdb\n"); + + /* Expect error due to insufficient output buffer size */ + memset(&buf, 0xcc, sizeof(buf)); + size = 0xdeadbeef; + ret = DeviceIoControl(device, IOCTL_SCSI_PASS_THROUGH, + &packet, sizeof(packet), &buf, sizeof(buf.packet), &size, NULL); + todo_wine ok(!ret, "DeviceIoControl succeeded\n"); + + /* Expect error due to insufficient input length */ + packet.Length = sizeof(SCSI_PASS_THROUGH) - 10; + + memset(&buf, 0xcc, sizeof(buf)); + size = 0xdeadbeef; + ret = DeviceIoControl(device, IOCTL_SCSI_PASS_THROUGH, + &packet, sizeof(packet), &buf, sizeof(buf), &size, NULL); + ok(!ret, "DeviceIoControl succeeded\n"); + + /* Test INQUIRY with same I/O buffer */ + memset(&buf, 0xcc, sizeof(buf)); + buf.packet.Length = sizeof(SCSI_PASS_THROUGH); + buf.packet.CdbLength = sizeof(inquiry_cmd); + buf.packet.DataIn = SCSI_IOCTL_DATA_IN; + buf.packet.DataTransferLength = inquiry_cmd[4]; + buf.packet.SenseInfoLength = 18; + buf.packet.TimeOutValue = 2; + buf.packet.DataBufferOffset = offsetof(struct scsi_pass_through_buffer, data); + buf.packet.SenseInfoOffset = offsetof(struct scsi_pass_through_buffer, sense); + memcpy(buf.packet.Cdb, inquiry_cmd, sizeof(inquiry_cmd)); + + size = 0xdeadbeef; + ret = DeviceIoControl(device, IOCTL_SCSI_PASS_THROUGH, + &buf, sizeof(buf), &buf, sizeof(buf), &size, NULL); + ok(ret, "DeviceIoControl failed, last=%ld\n", GetLastError()); + + trace("size %lu, sense %lu+%u, data %lu+%lu\n", + size, buf.packet.SenseInfoOffset, buf.packet.SenseInfoLength, + (DWORD)buf.packet.DataBufferOffset, buf.packet.DataTransferLength); + todo_wine ok(size == (DWORD)buf.packet.DataBufferOffset + buf.packet.DataTransferLength, "unexpected size %lu\n", size); + + ok((buf.data[0] & 0x1f) == READ_ONLY_DIRECT_ACCESS_DEVICE, "unexpected device type %d\n", buf.data[0] & 0x1f); + ok(buf.packet.Length == sizeof(SCSI_PASS_THROUGH), "got Length %u\n", buf.packet.Length); + ok(buf.packet.ScsiStatus == SCSISTAT_GOOD, "got ScsiStatus %u\n", buf.packet.ScsiStatus); + ok(buf.packet.CdbLength == sizeof(inquiry_cmd), "got CdbLength %u\n", buf.packet.CdbLength); + ok(buf.packet.DataIn == SCSI_IOCTL_DATA_IN, "got DataIn %u\n", buf.packet.DataIn); + ok(buf.packet.DataTransferLength == packet.Cdb[4], "got DataTransferLength %lu\n", buf.packet.DataTransferLength); + ok(!buf.packet.SenseInfoLength, "got SenseInfoLength %u\n", buf.packet.SenseInfoLength); + ok(buf.packet.DataBufferOffset == offsetof(struct scsi_pass_through_buffer, data), "got DataBufferOffset %lu\n", (DWORD)buf.packet.DataBufferOffset); + ok(buf.packet.SenseInfoOffset == offsetof(struct scsi_pass_through_buffer, sense), "got SenseInfoOffset %lu\n", buf.packet.SenseInfoOffset); + ok(!memcmp(buf.packet.Cdb, inquiry_cmd, sizeof(inquiry_cmd)), "got unexpected Cdb\n"); + + /* Test sense buffer */ + memset(&packet, 0, sizeof(packet)); + packet.Length = sizeof(SCSI_PASS_THROUGH); + packet.CdbLength = sizeof(read_cmd); + packet.DataIn = SCSI_IOCTL_DATA_IN; + packet.DataTransferLength = sizeof(buf.data); + packet.SenseInfoLength = 18; + packet.TimeOutValue = 2; + packet.DataBufferOffset = offsetof(struct scsi_pass_through_buffer, data); + packet.SenseInfoOffset = offsetof(struct scsi_pass_through_buffer, sense); + memcpy(packet.Cdb, read_cmd, sizeof(read_cmd)); + + memset(&buf, 0xcc, sizeof(buf)); + size = 0xdeadbeef; + ret = DeviceIoControl(device, IOCTL_SCSI_PASS_THROUGH, + &packet, sizeof(packet), &buf, sizeof(buf), &size, NULL); + ok(ret, "DeviceIoControl failed, last=%ld\n", GetLastError()); + + trace("size %lu, sense %lu+%u, data %lu+%lu\n", + size, buf.packet.SenseInfoOffset, buf.packet.SenseInfoLength, + (DWORD)buf.packet.DataBufferOffset, buf.packet.DataTransferLength); + if (buf.packet.DataTransferLength) + todo_wine ok(size == (DWORD)buf.packet.DataBufferOffset + buf.packet.DataTransferLength, "unexpected size %lu\n", size); + else + todo_wine ok(size == (DWORD)buf.packet.DataBufferOffset || size == buf.packet.SenseInfoOffset + buf.packet.SenseInfoLength, "unexpected size %lu\n", size); + + ok(buf.packet.Length == sizeof(SCSI_PASS_THROUGH), "got Length %u\n", buf.packet.Length); + ok(buf.packet.ScsiStatus == SCSISTAT_CHECK_CONDITION, "got ScsiStatus %d\n", buf.packet.ScsiStatus); + ok(buf.packet.CdbLength == packet.CdbLength, "got CdbLength %u\n", buf.packet.CdbLength); + ok(buf.packet.SenseInfoLength == 18, "got SenseInfoLength %u\n", buf.packet.SenseInfoLength); + ok((buf.sense[0] & 0x7f) == 0x70, "got Response Code %#x\n", buf.sense[0]); + sense_key = buf.sense[2] & 0xf; + ok(sense_key == SCSI_SENSE_NOT_READY || sense_key == SCSI_SENSE_ILLEGAL_REQUEST, "got Additional Sense Code %#x\n", sense_key); + ok(buf.packet.DataIn == packet.DataIn, "got DataIn %u\n", buf.packet.DataIn); + ok(!buf.packet.DataTransferLength || buf.packet.DataTransferLength == sizeof(buf.data), "got DataTransferLength %lu\n", buf.packet.DataTransferLength); + ok(buf.packet.TimeOutValue == packet.TimeOutValue, "got TimeOutValue %lu\n", buf.packet.TimeOutValue); + ok(buf.packet.DataBufferOffset == packet.DataBufferOffset, "got DataBufferOffset %lu\n", (DWORD)buf.packet.DataBufferOffset); + ok(buf.packet.SenseInfoOffset == packet.SenseInfoOffset, "got SenseInfoOffset %lu\n", buf.packet.SenseInfoOffset); + ok(!memcmp(buf.packet.Cdb, packet.Cdb, sizeof(packet.Cdb)), "got unexpected Cdb\n"); +} + static void test_cdrom_ioctl(void) { char drive_letter, drive_path[] = "A:\", drive_full_path[] = "\\.\A:"; @@ -1305,6 +1464,18 @@ static void test_cdrom_ioctl(void) test_dvd_read_structure(handle);
CloseHandle(handle); + + handle = CreateFileA(drive_full_path, GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); + if(handle == INVALID_HANDLE_VALUE) + { + trace("Failed to open the device (RW) : %lu\n", GetLastError()); + continue; + } + + test_scsi_pass_through(handle); + + CloseHandle(handle); }
}