This is the second part intended to replace !8120.
From: Akihiro Sagawa sagawa.aki@gmail.com
This partly reverts commit c3e06df9418. IDE6_MAJOR and IDE7_MAJOR definitions were introduced in Linux 2.3.1 and Linux 2.2 series support has been dropped since Wine 9.3 and later. As of commit eacd06264e2, we no longer use CDROM_SEND_PACKET ioctl. --- dlls/ntdll/unix/cdrom.c | 30 ------------------------------ 1 file changed, 30 deletions(-)
diff --git a/dlls/ntdll/unix/cdrom.c b/dlls/ntdll/unix/cdrom.c index aeedec86a65..9464b752b57 100644 --- a/dlls/ntdll/unix/cdrom.c +++ b/dlls/ntdll/unix/cdrom.c @@ -256,36 +256,6 @@ C_ASSERT(sizeof(internal_dvd_manufacturer_descriptor) == 2053); static NTSTATUS CDROM_ReadTOC(int, int, CDROM_TOC*); static NTSTATUS CDROM_GetStatusCode(int);
- -#ifdef linux - -# ifndef IDE6_MAJOR -# define IDE6_MAJOR 88 -# endif -# ifndef IDE7_MAJOR -# define IDE7_MAJOR 89 -# endif - -# ifdef CDROM_SEND_PACKET -/* structure for CDROM_PACKET_COMMAND ioctl */ -/* not all Linux versions have all the fields, so we define the - * structure ourselves to make sure */ -struct linux_cdrom_generic_command -{ - unsigned char cmd[CDROM_PACKET_SIZE]; - unsigned char *buffer; - unsigned int buflen; - int stat; - struct request_sense *sense; - unsigned char data_direction; - int quiet; - int timeout; - void *reserved[1]; -}; -# endif /* CDROM_SEND_PACKET */ - -#endif /* linux */ - /* FIXME: this is needed because we can't open simultaneously several times /dev/cdrom * this should be removed when a proper device interface is implemented *
From: Akihiro Sagawa sagawa.aki@gmail.com
--- dlls/ntdll/unix/cdrom.c | 76 +++++++++++++++++++++++------------------ 1 file changed, 43 insertions(+), 33 deletions(-)
diff --git a/dlls/ntdll/unix/cdrom.c b/dlls/ntdll/unix/cdrom.c index 9464b752b57..6fc444dee31 100644 --- a/dlls/ntdll/unix/cdrom.c +++ b/dlls/ntdll/unix/cdrom.c @@ -1598,7 +1598,7 @@ static NTSTATUS CDROM_RawRead(int fd, const RAW_READ_INFO* raw, void* buffer, DW * Implements IOCTL_SCSI_PASS_THROUGH_DIRECT * */ -static NTSTATUS CDROM_ScsiPassThroughDirect(int fd, PSCSI_PASS_THROUGH_DIRECT pPacket) +static NTSTATUS CDROM_ScsiPassThroughDirect(int fd, const SCSI_PASS_THROUGH_DIRECT *in_pkt, SCSI_PASS_THROUGH_DIRECT *out_pkt) { int ret = STATUS_NOT_SUPPORTED; #ifdef HAVE_SG_IO_HDR_T_INTERFACE_ID @@ -1609,33 +1609,33 @@ static NTSTATUS CDROM_ScsiPassThroughDirect(int fd, PSCSI_PASS_THROUGH_DIRECT pP int io; #endif
- if (pPacket->Length < sizeof(SCSI_PASS_THROUGH_DIRECT)) + if (in_pkt->Length < sizeof(SCSI_PASS_THROUGH_DIRECT)) 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->DataBuffer) + if (in_pkt->DataTransferLength > 0 && !in_pkt->DataBuffer) return STATUS_INVALID_PARAMETER;
#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 = pPacket->DataBuffer; - cmd.cmdp = pPacket->Cdb; - cmd.sbp = (unsigned char*)pPacket + pPacket->SenseInfoOffset; - cmd.timeout = pPacket->TimeOutValue*1000; + cmd.cmd_len = in_pkt->CdbLength; + cmd.mx_sb_len = in_pkt->SenseInfoLength; + cmd.dxfer_len = in_pkt->DataTransferLength; + cmd.dxferp = in_pkt->DataBuffer; + cmd.cmdp = (unsigned char*)in_pkt->Cdb; + cmd.sbp = (unsigned char*)out_pkt + in_pkt->SenseInfoOffset; + cmd.timeout = in_pkt->TimeOutValue*1000;
- switch (pPacket->DataIn) + switch (in_pkt->DataIn) { case SCSI_IOCTL_DATA_IN: cmd.dxfer_direction = SG_DXFER_FROM_DEV; @@ -1652,25 +1652,25 @@ static NTSTATUS CDROM_ScsiPassThroughDirect(int fd, PSCSI_PASS_THROUGH_DIRECT pP
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 = pPacket->DataBuffer; - 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.buffer = in_pkt->DataBuffer; + 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.direction = kSCSIDataTransfer_FromInitiatorToTarget; @@ -1693,29 +1693,39 @@ static NTSTATUS CDROM_ScsiPassThroughDirect(int fd, PSCSI_PASS_THROUGH_DIRECT pP switch (cmd.status) { case kSCSITaskStatus_TaskTimeoutOccurred: return STATUS_TIMEOUT; - break; case kSCSITaskStatus_ProtocolTimeoutOccurred: return STATUS_IO_TIMEOUT; - break; case kSCSITaskStatus_DeviceNotResponding: return STATUS_DEVICE_BUSY; - break; case kSCSITaskStatus_DeviceNotPresent: return STATUS_NO_SUCH_DEVICE; - break; case kSCSITaskStatus_DeliveryFailure: return STATUS_DEVICE_PROTOCOL_ERROR; - break; case kSCSITaskStatus_No_Status: default: return STATUS_UNSUCCESSFUL; - break; } }
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->DataBuffer = in_pkt->DataBuffer; + out_pkt->SenseInfoOffset = in_pkt->SenseInfoOffset; + memcpy(out_pkt->Cdb, in_pkt->Cdb, sizeof(in_pkt->Cdb)); + } + } + return ret; }
@@ -3017,9 +3027,9 @@ NTSTATUS cdrom_DeviceIoControl( HANDLE device, HANDLE event, PIO_APC_ROUTINE apc break; case IOCTL_SCSI_PASS_THROUGH_DIRECT: sz = sizeof(SCSI_PASS_THROUGH_DIRECT); - 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_DIRECT)) status = STATUS_BUFFER_TOO_SMALL; - else status = CDROM_ScsiPassThroughDirect(fd, out_buffer); + else status = CDROM_ScsiPassThroughDirect(fd, in_buffer, out_buffer); break; case IOCTL_SCSI_PASS_THROUGH: if (in_wow64_call())
From: Akihiro Sagawa sagawa.aki@gmail.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=58257 --- dlls/ntdll/unix/cdrom.c | 101 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 97 insertions(+), 4 deletions(-)
diff --git a/dlls/ntdll/unix/cdrom.c b/dlls/ntdll/unix/cdrom.c index 6fc444dee31..08365087f49 100644 --- a/dlls/ntdll/unix/cdrom.c +++ b/dlls/ntdll/unix/cdrom.c @@ -232,6 +232,23 @@ typedef struct _SCSI_PASS_THROUGH32 UCHAR Cdb[16]; } SCSI_PASS_THROUGH32, *PSCSI_PASS_THROUGH32;
+typedef struct _SCSI_PASS_THROUGH_DIRECT32 + { + USHORT Length; + UCHAR ScsiStatus; + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; + UCHAR CdbLength; + UCHAR SenseInfoLength; + UCHAR DataIn; + ULONG DataTransferLength; + ULONG TimeOutValue; + ULONG DataBuffer; /* actually, VOID* POINTER_32 */ + ULONG SenseInfoOffset; + UCHAR Cdb[16]; +} SCSI_PASS_THROUGH_DIRECT32, *PSCSI_PASS_THROUGH_DIRECT32; + /* The documented format of DVD_LAYER_DESCRIPTOR is wrong. Even the format in the * DDK's header is wrong. There are four bytes at the start defined by * MMC-5. The first two are the size of the structure in big-endian order as @@ -1729,6 +1746,72 @@ static NTSTATUS CDROM_ScsiPassThroughDirect(int fd, const SCSI_PASS_THROUGH_DIRE return ret; }
+static NTSTATUS CDROM_ScsiPassThroughDirect32(int fd, const SCSI_PASS_THROUGH_DIRECT32 *in_pkt32, SCSI_PASS_THROUGH_DIRECT32 *out_pkt32) +{ + SCSI_PASS_THROUGH_DIRECT *pkt; + ULONG_PTR ptr; + NTSTATUS ret; + + if (in_pkt32->Length < sizeof(SCSI_PASS_THROUGH_DIRECT32)) + return STATUS_BUFFER_TOO_SMALL; + + if (in_pkt32->CdbLength > 16) + return STATUS_INVALID_PARAMETER; + +#ifdef SENSEBUFLEN + if (in_pkt32->SenseInfoLength > SENSEBUFLEN) + return STATUS_INVALID_PARAMETER; +#endif + + if (in_pkt32->SenseInfoLength > 0) + { + if (in_pkt32->SenseInfoOffset < sizeof(SCSI_PASS_THROUGH_DIRECT32)) + 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_DIRECT) + in_pkt32->SenseInfoLength); + if (!pkt) return STATUS_NO_MEMORY; + + pkt->Length = sizeof(SCSI_PASS_THROUGH_DIRECT); + 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->DataBuffer = ULongToPtr(in_pkt32->DataBuffer); + pkt->SenseInfoOffset = sizeof(SCSI_PASS_THROUGH_DIRECT); + memcpy(pkt->Cdb, in_pkt32->Cdb, sizeof(pkt->Cdb)); + + ret = CDROM_ScsiPassThroughDirect(fd, pkt, pkt); + if (NT_ERROR(ret)) goto done; + + out_pkt32->Length = sizeof(SCSI_PASS_THROUGH_DIRECT32); + 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->DataBuffer = in_pkt32->DataBuffer; + 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); + +done: + free(pkt); + return ret; +} + /****************************************************************** * CDROM_ScsiPassThrough * Implements IOCTL_SCSI_PASS_THROUGH @@ -3026,10 +3109,20 @@ NTSTATUS cdrom_DeviceIoControl( HANDLE device, HANDLE event, PIO_APC_ROUTINE apc else status = CDROM_GetAddress(fd, out_buffer); break; case IOCTL_SCSI_PASS_THROUGH_DIRECT: - sz = sizeof(SCSI_PASS_THROUGH_DIRECT); - if (in_buffer == NULL || out_buffer == NULL) status = STATUS_INVALID_PARAMETER; - else if (out_size < sizeof(SCSI_PASS_THROUGH_DIRECT)) status = STATUS_BUFFER_TOO_SMALL; - else status = CDROM_ScsiPassThroughDirect(fd, in_buffer, out_buffer); + if (in_wow64_call()) + { + sz = sizeof(SCSI_PASS_THROUGH_DIRECT32); + if (in_buffer == NULL || out_buffer == NULL) status = STATUS_INVALID_PARAMETER; + else if (out_size < sizeof(SCSI_PASS_THROUGH_DIRECT32)) status = STATUS_BUFFER_TOO_SMALL; + else status = CDROM_ScsiPassThroughDirect32(fd, in_buffer, out_buffer); + } + else + { + sz = sizeof(SCSI_PASS_THROUGH_DIRECT); + if (in_buffer == NULL || out_buffer == NULL) status = STATUS_INVALID_PARAMETER; + else if (out_size < sizeof(SCSI_PASS_THROUGH_DIRECT)) status = STATUS_BUFFER_TOO_SMALL; + else status = CDROM_ScsiPassThroughDirect(fd, in_buffer, out_buffer); + } break; case IOCTL_SCSI_PASS_THROUGH: if (in_wow64_call())
From: Akihiro Sagawa sagawa.aki@gmail.com
--- dlls/kernel32/tests/volume.c | 137 +++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+)
diff --git a/dlls/kernel32/tests/volume.c b/dlls/kernel32/tests/volume.c index 6de12add2c6..60374ca4139 100644 --- a/dlls/kernel32/tests/volume.c +++ b/dlls/kernel32/tests/volume.c @@ -1425,6 +1425,142 @@ static void test_scsi_pass_through(HANDLE device) ok(!memcmp(buf.packet.Cdb, packet.Cdb, sizeof(packet.Cdb)), "got unexpected Cdb\n"); }
+static void test_scsi_pass_through_direct(HANDLE device) +{ + struct scsi_pass_through_direct_buffer { + SCSI_PASS_THROUGH_DIRECT packet; + UCHAR sense[32]; + } buf; + SCSI_PASS_THROUGH_DIRECT packet; + UCHAR data[2048]; + 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_DIRECT); + packet.CdbLength = sizeof(inquiry_cmd); + packet.DataIn = SCSI_IOCTL_DATA_IN; + packet.DataTransferLength = inquiry_cmd[4]; + packet.SenseInfoLength = 0; + packet.TimeOutValue = 2; + packet.DataBuffer = data; + packet.SenseInfoOffset = 0; + memcpy(packet.Cdb, inquiry_cmd, sizeof(inquiry_cmd)); + + memset(&buf, 0xcc, sizeof(buf)); + memset(data, 0xcc, sizeof(data)); + size = 0xdeadbeef; + ret = DeviceIoControl(device, IOCTL_SCSI_PASS_THROUGH_DIRECT, + &packet, sizeof(packet), &buf.packet, sizeof(buf.packet), &size, NULL); + ok(ret, "DeviceIoControl failed, last=%ld\n", GetLastError()); + + ok(size == sizeof(SCSI_PASS_THROUGH_DIRECT), "unexpected size %lu\n", size); + + ok((data[0] & 0x1f) == READ_ONLY_DIRECT_ACCESS_DEVICE, "unexpected device type %d\n", data[0] & 0x1f); + ok(buf.packet.Length == sizeof(SCSI_PASS_THROUGH_DIRECT), "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.DataBuffer == packet.DataBuffer, "got DataBuffer %p\n", buf.packet.DataBuffer); + 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)); + memset(data, 0xcc, sizeof(data)); + packet.SenseInfoLength = 18; + packet.SenseInfoOffset = offsetof(struct scsi_pass_through_direct_buffer, sense); + size = 0xdeadbeef; + ret = DeviceIoControl(device, IOCTL_SCSI_PASS_THROUGH_DIRECT, + &packet, sizeof(packet), &buf.packet, 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_DIRECT) - 10; + + memset(&buf, 0xcc, sizeof(buf)); + memset(data, 0xcc, sizeof(data)); + size = 0xdeadbeef; + ret = DeviceIoControl(device, IOCTL_SCSI_PASS_THROUGH_DIRECT, + &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)); + memset(data, 0xcc, sizeof(data)); + buf.packet.Length = sizeof(SCSI_PASS_THROUGH_DIRECT); + 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.DataBuffer = data; + buf.packet.SenseInfoOffset = offsetof(struct scsi_pass_through_direct_buffer, sense); + memcpy(buf.packet.Cdb, inquiry_cmd, sizeof(inquiry_cmd)); + + size = 0xdeadbeef; + ret = DeviceIoControl(device, IOCTL_SCSI_PASS_THROUGH_DIRECT, + &buf, sizeof(buf), &buf, sizeof(buf), &size, NULL); + ok(ret, "DeviceIoControl failed, last=%ld\n", GetLastError()); + + trace("size %lu, sense %lu+%u, data %lu\n", + size, buf.packet.SenseInfoOffset, buf.packet.SenseInfoLength, buf.packet.DataTransferLength); + ok(size == sizeof(SCSI_PASS_THROUGH_DIRECT), "unexpected size %lu\n", size); + + ok((data[0] & 0x1f) == READ_ONLY_DIRECT_ACCESS_DEVICE, "unexpected device type %d\n", data[0] & 0x1f); + ok(buf.packet.Length == sizeof(SCSI_PASS_THROUGH_DIRECT), "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.DataBuffer == data, "got DataBuffer %p\n", buf.packet.DataBuffer); + ok(buf.packet.SenseInfoOffset == offsetof(struct scsi_pass_through_direct_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_DIRECT); + packet.CdbLength = sizeof(read_cmd); + packet.DataIn = SCSI_IOCTL_DATA_IN; + packet.DataTransferLength = sizeof(data); + packet.SenseInfoLength = 18; + packet.TimeOutValue = 2; + packet.DataBuffer = data; + packet.SenseInfoOffset = offsetof(struct scsi_pass_through_direct_buffer, sense); + memcpy(packet.Cdb, read_cmd, sizeof(read_cmd)); + + memset(&buf, 0xcc, sizeof(buf)); + memset(data, 0xcc, sizeof(data)); + size = 0xdeadbeef; + ret = DeviceIoControl(device, IOCTL_SCSI_PASS_THROUGH_DIRECT, + &packet, sizeof(packet), &buf, sizeof(buf), &size, NULL); + ok(ret, "DeviceIoControl failed, last=%ld\n", GetLastError()); + + trace("size %lu, sense %lu+%u, data %lu\n", + size, buf.packet.SenseInfoOffset, buf.packet.SenseInfoLength, buf.packet.DataTransferLength); + todo_wine ok(size == buf.packet.SenseInfoOffset + buf.packet.SenseInfoLength, "unexpected size %lu\n", size); + + ok(buf.packet.Length == sizeof(SCSI_PASS_THROUGH_DIRECT), "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(data), "got DataTransferLength %lu\n", buf.packet.DataTransferLength); + ok(buf.packet.TimeOutValue == packet.TimeOutValue, "got TimeOutValue %lu\n", buf.packet.TimeOutValue); + ok(buf.packet.DataBuffer == packet.DataBuffer, "got DataBuffer %p\n", buf.packet.DataBuffer); + 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:"; @@ -1474,6 +1610,7 @@ static void test_cdrom_ioctl(void) }
test_scsi_pass_through(handle); + test_scsi_pass_through_direct(handle);
CloseHandle(handle); }