cdrom: gdrom: fix block I/O and capacity setting
v2 cover cdrom: gdrom: fix block I/O and capacity setting
Hi all,
This series fixes a gdrom driver Oops due to bad MMIO register access and fixes the missing updates of the block layer gendisk capacity that prevented ISO9660 mounts from working.
The change was tested on real Sega Dreamcast devices (PAL-E, NTSC-J, NTSC-U) with physical CD-R discs and with GDEMU emulated discs. Before:
Oops on mount and an unusable drive. After: Successfully able to mount and use the inserted medium.
Thanks,
Florian
---v1->v2: for "cdrom: gdrom: replace port I/O with MMIO accessors": Don't
use helper functions with io.*_rep(), but writesw() and readsw() local in the respective functions. Improved failure case of gdrom_update_capacity() in gdrom_bdops_open().
v1: https://lore.kernel.org/linux-sh/[email protected]/
Florian Fuchs (2):
cdrom: gdrom: replace port I/O with MMIO accessors
cdrom: gdrom: update gendisk capacity on open
drivers/cdrom/gdrom.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-)
base-commit: 6de23f81a5e08be8fbf5e8d7e9febc72a5b5f27f
Signature · 1 line
2.43.0
PATCH v2 1/2 cdrom: gdrom: replace port I/O with MMIO accessors
GDROM_DATA_REG is a memory-mapped data register, but the driver uses outsw() and insw() only for this register. Replace this with MMIO accessors readsw() / writesw().
Before, it oopsed accessing the data register, as the io_port_base P2SEG gets added to the argument in outsw() / insw(), which leads to an unusable drive:
BUG: unable to handle kernel paging request at 405f7080
PC: [<8c28d5b4>] gdrom_spicommand+0x6c/0xb0---v1->v2: Don't use helper functions with io.*_rep(), but writesw() and
readsw() local in the respective functions
v1: https://lore.kernel.org/linux-sh/[email protected]/
--- drivers/cdrom/gdrom.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/cdrom/gdrom.c +4 -4
@@ -198,7 +198,7 @@ static void gdrom_spicommand(void *spi_string, int buflen)gdrom_getsense (NULL );return ; } -outsw (GDROM_DATA_REG , cmd,6 ); +writesw ((void __iomem *)GDROM_DATA_REG , cmd,6 ); }
@@ -282,7 +282,7 @@ static int gdrom_readtoc_cmd(struct gdromtoc *toc, int session) err = -EINVAL ; goto cleanup_readtoc; } -insw (GDROM_DATA_REG , toc, tocsize/2 ); +readsw ((void __iomem *)GDROM_DATA_REG , toc, tocsize /2 );if (gd.status &0x01 ) err = -EINVAL ;
@@ -433,7 +433,7 @@ static int gdrom_getsense(short *bufstring) GDROM_DEFAULT_TIMEOUT);if (gd.pending) goto cleanup_sense; -insw (GDROM_DATA_REG , &sense, sense_command->buflen/2 ); +readsw ((void __iomem *)GDROM_DATA_REG , &sense, sense_command->buflen /2 );if (sense[1 ] &40 ) {pr_info ("Drive not ready - command aborted\n" ); goto cleanup_sense;
@@ -612,7 +612,7 @@ static blk_status_t gdrom_readdisk_dma(struct request *req)cpu_relax (); gd.pending =1 ; gd.transfer =1 ; -outsw (GDROM_DATA_REG , &read_command->cmd,6 ); +writesw ((void __iomem *)GDROM_DATA_REG , read_command->cmd,6 ); timeout = jiffies +HZ /2 ;/* Wait for any pending DMA to finish */ while (__raw_readb(GDROM_DMA_STATUS_REG) &&
Signature · 1 line
2.43.0
Re: [PATCH v2 1/2] cdrom: gdrom: replace port I/O with MMIO accessors
Quoted 4 lines · Florian Fuchs
GDROM_DATA_REGis a memory-mapped data register, but the driver usesoutsw()andinsw()only for this register. Replace this with MMIO accessorsreadsw()/writesw().
Quoted 8 lines
Before, it oopsed accessing the data register, as the
io_port_baseP2SEG gets added to the argument inoutsw()/insw(), which leads to an unusable drive:BUG: unable to handle kernel paging request at 405f7080 PC: [<8c28d5b4>] gdrom_spicommand+0x6c/0xb0Signed-off-by Florian Fuchs <[email protected]>
Quoted 53 lines
---
v1->v2: Don't use helper functions with io.*_rep(), butwritesw()and
readsw()local in the respective functionsv1: https://lore.kernel.org/linux-sh/[email protected]/
--- drivers/cdrom/gdrom.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)drivers/cdrom/gdrom.c +3
-3@@ -198,7 +198,7 @@ static void gdrom_spicommand(void *spi_string, int buflen)gdrom_getsense (NULL );return ; } -outsw (GDROM_DATA_REG , cmd,6 ); +writesw ((void __iomem *)GDROM_DATA_REG , cmd,6 ); }@@ -282,7 +282,7 @@ static int gdrom_readtoc_cmd(struct gdromtoc *toc, int session) err = -EINVAL ; goto cleanup_readtoc; } -insw (GDROM_DATA_REG , toc, tocsize/2 ); +readsw ((void __iomem *)GDROM_DATA_REG , toc, tocsize /2 );if (gd.status &0x01 ) err = -EINVAL ;@@ -433,7 +433,7 @@ static int gdrom_getsense(short *bufstring) GDROM_DEFAULT_TIMEOUT);if (gd.pending) goto cleanup_sense; -insw (GDROM_DATA_REG , &sense, sense_command->buflen/2 ); +readsw ((void __iomem *)GDROM_DATA_REG , &sense, sense_command->buflen /2 );if (sense[1 ] &40 ) {pr_info ("Drive not ready - command aborted\n" );drivers/cdrom/gdrom.c +1
-1goto cleanup_sense;@@ -612,7 +612,7 @@ static blk_status_t gdrom_readdisk_dma(struct request *req)cpu_relax (); gd.pending =1 ; gd.transfer =1 ; -outsw (GDROM_DATA_REG , &read_command->cmd,6 ); +writesw ((void __iomem *)GDROM_DATA_REG , read_command->cmd,6 ); timeout = jiffies +HZ /2 ;/* Wait for any pending DMA to finish */ while (
__raw_readb(GDROM_DMA_STATUS_REG)&&
Re: [PATCH v2 1/2] cdrom: gdrom: replace port I/O with MMIO accessors
In reply to Florian FuchsQuoted 1 line · Florian Fuchs
Not tested this on real hardware but I can confirm it addresses the identified bug and is logically correct.
Adrian McMenamin
John Paul Adrian Glaubitz
maintainerRe: [PATCH v2 1/2] cdrom: gdrom: replace port I/O with MMIO accessors
Hi Adrian,
Quoted 4 lines · Adrian McMenamin
Quoted 1 line · Florian Fuchs
Not tested this on real hardware but I can confirm it addresses the identified bug and is logically correct.
Want to add your Reviewed-by maybe?
Adrian
Signature · 4 lines
.''`. John Paul Adrian Glaubitz : :' : Debian Developer `. `' Physicist `- GPG: 62FF 8A75 84E0 2956 9546 0006 7426 3B37 F5B5 F913
Re: [PATCH v2 1/2] cdrom: gdrom: replace port I/O with MMIO accessors
In reply to Florian FuchsQuoted 1 line · Florian Fuchs
This patch addresses the bug and is logically correct and so looks good to me.
PATCH v2 2/2 cdrom: gdrom: update gendisk capacity on open
In reply to Florian FuchsUpdate the gendisk capacity of the media. Without the capacity, the block reads fail before reaching the request queue, which prevented ISO9660 mounts. Refresh the capacity from the TOC leadout in gdrom_bdops_open() so it checks the inserted media.
---v1->v2: no change for gdrom_update_capacity(), but for
gdrom_bdops_open(): handle the failure case when gdrom_update_capacity() fails but previous cdrom_open() succeeded, to cleanup the successful cdrom_open() with cdrom_release()
v1: https://lore.kernel.org/linux-sh/[email protected]/
--- drivers/cdrom/gdrom.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+)
drivers/cdrom/gdrom.c +25 -0
@@ -474,6 +474,25 @@ static const struct cdrom_device_ops gdrom_ops = { CDC_RESET | CDC_DRIVE_STATUS | CDC_CD_R, }; +static int gdrom_update_capacity (void ) +{ +sector_t cap; +int ret; + +if (gdrom_drivestatus (gd.cd_info,CDSL_CURRENT ) !=CDS_DISC_OK ) { +set_capacity (gd.disk,0 ); +return -ENOMEDIUM ; + } + ret =gdrom_readtoc_cmd (gd.toc,0 ); +if (ret) { +set_capacity (gd.disk,0 ); +return ret; + } + cap = (sector_t )get_entry_lba (gd.toc->leadout) *GD_TO_BLK ; +set_capacity (gd.disk, cap); +return 0 ; +} +static int gdrom_bdops_open (struct gendisk *disk,blk_mode_t mode) {int ret;
@@ -482,6 +501,12 @@ static int gdrom_bdops_open(struct gendisk *disk, blk_mode_t mode)mutex_lock (&gdrom_mutex); ret =cdrom_open (gd.cd_info, mode); +if (ret) + goto out; + ret =gdrom_update_capacity (); +if (ret) +cdrom_release (gd.cd_info); +out:mutex_unlock (&gdrom_mutex);return ret; }
Signature · 1 line
2.43.0
Re: [PATCH v2 2/2] cdrom: gdrom: update gendisk capacity on open
Quoted 61 lines · Florian Fuchs
Update the gendisk capacity of the media. Without the capacity, the block reads fail before reaching the request queue, which prevented ISO9660 mounts. Refresh the capacity from the TOC leadout in
gdrom_bdops_open()so it checks the inserted media.Signed-off-by Florian Fuchs <[email protected]>---
v1->v2: no change forgdrom_update_capacity(), but for
gdrom_bdops_open(): handle the failure case whengdrom_update_capacity()fails but previouscdrom_open()
succeeded,
to cleanup the successfulcdrom_open()withcdrom_release()v1: https://lore.kernel.org/linux-sh/[email protected]/
--- drivers/cdrom/gdrom.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+)drivers/cdrom/gdrom.c +25
-0@@ -474,6 +474,25 @@ static const struct cdrom_device_ops gdrom_ops = { CDC_RESET | CDC_DRIVE_STATUS | CDC_CD_R, }; +static int gdrom_update_capacity (void ) +{ +sector_t cap; +int ret; + +if (gdrom_drivestatus (gd.cd_info,CDSL_CURRENT ) !=CDS_DISC_OK ) { +set_capacity (gd.disk,0 ); +return -ENOMEDIUM ; + } + ret =gdrom_readtoc_cmd (gd.toc,0 ); +if (ret) { +set_capacity (gd.disk,0 ); +return ret; + } + cap = (sector_t )get_entry_lba (gd.toc->leadout) *GD_TO_BLK ; +set_capacity (gd.disk, cap); +return 0 ; +} +static int gdrom_bdops_open (struct gendisk *disk,blk_mode_t mode) {int ret;@@ -482,6 +501,12 @@ static int gdrom_bdops_open(struct gendisk *disk, blk_mode_t mode) mutex_lock(&gdrom_mutex); ret =cdrom_open (gd.cd_info, mode); +if (ret) + goto out; + ret =gdrom_update_capacity (); +if (ret) +cdrom_release (gd.cd_info); +out:mutex_unlock (&gdrom_mutex);return ret;
Quoted 1 line
}
Hey Florian,
thanks for v2!
PS. I found the reason behind mount failing for the first time after a disc swap - you need to send a dummy 0x0 SPI command to "sink" the pending UNIT_ATTENTION error, otherwise it will permeate at the next command executed, which in our case is gdrom_preparedisk_cmd().
I already sent you a WIP patch via IRC. Once you test it, would you consider including it in this series and sending v3?
Cheers,
Artur