SCSI command 0xAD (GPCMD_READ_DVD_STRUCTURE) with the eighth byte of the command set to 0x00 (DVD_STRUCT_PHYSICAL) returns physical disc information for DVDs and blu-rays. On success, the command returns status 0, and for ordinary CDs, the command returns the error status 0x02 (SAM_STAT_CHECK_CONDITION). The format of the data returned is different for blu-rays than for DVDs, and the second byte of the command indicates whether to return DVD information or blu-ray information. (My LG WH16NS40 drive actually ignores the second byte when there is a DVD in the drive, but it returns SAM_STAT_CHECK_CONDITION when there is a blu-ray in the drive and the second byte is not 0x01.) Windows does not distinguish between DVDs and blu-rays in IOCTL_DISK_GET_MEDIA_TYPES, so if the SCSI command succeeds for either disc type, report FILE_DEVICE_DVD.
More specific media information is still not implemented.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=57790
-- v3: ntdll: Detect the optical disc type on Linux using a SCSI command.
From: Alex Henrie alexhenrie24@gmail.com
SCSI command 0xAD (GPCMD_READ_DVD_STRUCTURE) with the eighth byte of the command set to 0x00 (DVD_STRUCT_PHYSICAL) returns physical disc information for DVDs and blu-rays. On success, the command returns status 0, and for ordinary CDs, the command returns the error status 0x02 (SAM_STAT_CHECK_CONDITION). The format of the data returned is different for blu-rays than for DVDs, and the second byte of the command indicates whether to return DVD information or blu-ray information. (My LG WH16NS40 drive actually ignores the second byte when there is a DVD in the drive, but it returns SAM_STAT_CHECK_CONDITION when there is a blu-ray in the drive and the second byte is not 0x01.) Windows does not distinguish between DVDs and blu-rays in IOCTL_DISK_GET_MEDIA_TYPES, so if the SCSI command succeeds for either disc type, report FILE_DEVICE_DVD.
More specific media information is still not implemented.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=57790 --- dlls/ntdll/unix/cdrom.c | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-)
diff --git a/dlls/ntdll/unix/cdrom.c b/dlls/ntdll/unix/cdrom.c index 5a700940ceb..677a1b9a012 100644 --- a/dlls/ntdll/unix/cdrom.c +++ b/dlls/ntdll/unix/cdrom.c @@ -758,11 +758,41 @@ static NTSTATUS CDROM_GetDriveGeometry(int dev, int fd, DISK_GEOMETRY* dg) * CDROM_GetMediaType * */ -static NTSTATUS CDROM_GetMediaType(int dev, GET_MEDIA_TYPES* medtype) +static NTSTATUS CDROM_GetMediaType(int dev, int fd, GET_MEDIA_TYPES* medtype) { - FIXME(": faking success\n"); + FIXME("semi-stub\n"); medtype->DeviceType = FILE_DEVICE_CD_ROM; medtype->MediaInfoCount = 0; + +#if defined(HAVE_SG_IO_HDR_T_INTERFACE_ID) && defined(HAVE_LINUX_CDROM_H) + for (unsigned char disc_type = 0 /* DVD */; disc_type <= 1 /* blu-ray */; disc_type++) + { + unsigned char buf[255]; + unsigned char read_disc_struct_cmd[12] = { GPCMD_READ_DVD_STRUCTURE, disc_type, 0x00, 0x00, 0x00, 0x00, + 0x00, DVD_STRUCT_PHYSICAL, 0x00, sizeof(buf) }; + sg_io_hdr_t iocmd = + { + .interface_id = 'S', + .dxfer_direction = SG_DXFER_FROM_DEV, + .cmd_len = sizeof(read_disc_struct_cmd), + .dxfer_len = sizeof(buf), + .dxferp = buf, + .cmdp = read_disc_struct_cmd, + .timeout = 1000, + }; + int err; + + if ((err = ioctl(fd, SG_IO, &iocmd))) + return CDROM_GetStatusCode(err); + + if (iocmd.status == 0) + { + medtype->DeviceType = FILE_DEVICE_DVD; + break; + } + } +#endif + return STATUS_SUCCESS; }
@@ -2908,7 +2938,7 @@ NTSTATUS cdrom_DeviceIoControl( HANDLE device, HANDLE event, PIO_APC_ROUTINE apc sz = sizeof(GET_MEDIA_TYPES); if (in_buffer != NULL || in_size != 0) status = STATUS_INVALID_PARAMETER; else if (out_size < sz) status = STATUS_BUFFER_TOO_SMALL; - else status = CDROM_GetMediaType(dev, out_buffer); + else status = CDROM_GetMediaType(dev, fd, out_buffer); break;
case IOCTL_STORAGE_GET_DEVICE_NUMBER:
On Sun May 25 18:44:44 2025 +0000, Jinoh Kang wrote:
Any chance it could be a driver bug?
Since you asked, I dug into the kernel code today and learned that Linux's DVD_READ_STRUCT ioctl is implemented on top of SCSI command 0xAD which returns physical disc information (among other things). The data returned from command 0xAD has a completely different format in the [DVD](https://www.t10.org/ftp/t10/document.97/97-108r0.pdf#page=36) and [Blu-ray](https://www.t10.org/ftp/t10/document.04/04-318r0.pdf#page=32) specifications. The Blu-ray spec changes the second byte of the SCSI command, which was reserved in the DVD spec, to a value that indicates whether a DVD struct or a blu-ray struct should be returned. It doesn't surprise me that the SCSI command fails to return any DVD information when a blu-ray is in the drive, and consequently Linux fails to return anything for DVD_STRUCT_PHYSICAL.
What we could do is send command 0xAD twice to see if we can get the DVD struct or the blu-ray struct. If either one succeeds, we can be confident in reporting FILE_DEVICE_DVD. I've pushed a new patch that does exactly that. Hopefully it makes everyone happy.