debugging patch for ide-cd/isofs

Bill Hawes (whawes@star.net)
Mon, 14 Sep 1998 16:03:08 -0400


This is a multi-part message in MIME format.
--------------6D4230752FBDF988D8346C86
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

I've put together a patch to help debug what looks like a timing
interaction between isofs and ide-cd, and would like anyone who can
trigger a "DMA disabled" message with a CD-ROM to give it a try.

My theory is that ide-cd is somehow becoming confused as to whether a
DMA operation is pending, and the drive responds with an error. The
patch prints out the status of the info->dma field for the operations
occurring while the isofs superblock is being set up.

So give it a try and post the log messages if you're able to trigger a
"DMA disabled" ...

Regards,
Bill
--------------6D4230752FBDF988D8346C86
Content-Type: text/plain; charset=us-ascii; name="isofs_121-patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="isofs_121-patch"

--- linux-2.1.121/fs/isofs/inode.c.old Thu Sep 10 08:07:04 1998
+++ linux-2.1.121/fs/isofs/inode.c Mon Sep 14 15:40:55 1998
@@ -30,12 +30,16 @@
#include <asm/system.h>
#include <asm/uaccess.h>

+/* temporary for debugging */
+#include <linux/utsname.h>
+#define ide_cd_debug (system_utsname.sysname[64])
+
/*
* We have no support for "multi volume" CDs, but more and more disks carry
* wrong information within the volume descriptors.
*/
#define IGNORE_WRONG_MULTI_VOLUME_SPECS
-#define BEQUIET
+/* #define BEQUIET */

#ifdef LEAK_CHECK
static int check_malloc = 0;
@@ -448,27 +452,30 @@
struct super_block *isofs_read_super(struct super_block *s, void *data,
int silent)
{
- struct buffer_head * bh = NULL, *pri_bh = NULL;
- unsigned int blocksize;
- unsigned int blocksize_bits;
kdev_t dev = s->s_dev;
+ struct buffer_head * bh = NULL, *pri_bh = NULL;
struct hs_primary_descriptor * h_pri = NULL;
struct iso_primary_descriptor * pri = NULL;
struct iso_supplementary_descriptor *sec = NULL;
struct iso_directory_record * rootp;
+ int joliet_level = 0;
int high_sierra;
int iso_blknum, block;
- int joliet_level = 0;
int orig_zonesize;
+ int table;
+ unsigned int blocksize, blocksize_bits;
unsigned int vol_desc_start;
+ unsigned long first_data_zone;
struct inode * inode;
struct iso9660_options opt;
- int table;

MOD_INC_USE_COUNT;
/* lock before any blocking operations */
lock_super(s);

+ /* turn on ide-cd debugging */
+ ide_cd_debug = 1;
+
if (!parse_options((char *) data, &opt))
goto out_unlock;

@@ -511,11 +518,13 @@
}
}

+printk("isofs_read_super: blocksize=%d, using %d\n", blocksize, opt.blocksize);
set_blocksize(dev, opt.blocksize);

s->u.isofs_sb.s_high_sierra = high_sierra = 0; /* default is iso9660 */

vol_desc_start = isofs_get_last_session(dev);
+printk("isofs_read_super: last session start=%d\n", vol_desc_start);

for (iso_blknum = vol_desc_start+16;
iso_blknum < vol_desc_start+100; iso_blknum++)
@@ -526,6 +535,7 @@
block = iso_blknum << (ISOFS_BLOCK_BITS-blocksize_bits);
if (!(bh = bread(dev, block, opt.blocksize)))
goto out_no_read;
+printk("isofs_read_super: read block=%d, blksize=%d\n", block, opt.blocksize);

vdp = (struct iso_volume_descriptor *)bh->b_data;
hdp = (struct hs_volume_descriptor *)bh->b_data;
@@ -538,6 +548,7 @@
high_sierra = 1;
opt.rock = 'n';
h_pri = (struct hs_primary_descriptor *)vdp;
+printk("isofs_read_super: hs, bh=%p, h_pri=%p\n", bh, h_pri);
goto root_found;
}

@@ -550,6 +561,7 @@
/* Save the buffer in case we need it ... */
pri_bh = bh;
bh = NULL;
+printk("isofs_read_super: saving pri, pri_bh=%p, pri=%p\n", pri_bh, pri);
}
}
#ifdef CONFIG_JOLIET
@@ -567,6 +579,7 @@
printk(KERN_DEBUG"ISO 9660 Extensions: Microsoft Joliet Level %d\n",
joliet_level);
}
+printk("isofs_read_super: found sec, bh=%p, sec=%p\n", bh, sec);
goto root_found;
} else {
/* Unknown supplementary volume descriptor */
@@ -592,13 +605,13 @@

root_found:
brelse(pri_bh);
- s->u.isofs_sb.s_joliet_level = joliet_level;

if (joliet_level && opt.rock == 'n') {
/* This is the case of Joliet with the norock mount flag.
* A disc with both Joliet and Rock Ridge is handled later
*/
pri = (struct iso_primary_descriptor *) sec;
+printk("isofs_read_super: setting pri to sec=%p\n", sec);
}

if(high_sierra){
@@ -612,6 +625,7 @@
s->u.isofs_sb.s_max_size = isonum_733(h_pri->volume_space_size);
} else {
rootp = (struct iso_directory_record *) pri->root_directory_record;
+printk("isofs_read_super: using pri=%p, got rootp=%p\n", pri, rootp);
#ifndef IGNORE_WRONG_MULTI_VOLUME_SPECS
if (isonum_723 (pri->volume_set_size) != 1)
goto out_no_support;
@@ -623,10 +637,7 @@

s->u.isofs_sb.s_ninodes = 0; /* No way to figure this out easily */

- /* RDE: convert log zone size to bit shift */
-
orig_zonesize = s -> u.isofs_sb.s_log_zone_size;
-
/*
* If the zone size is smaller than the hardware sector size,
* this is a fatal error. This would occur if the disc drive
@@ -637,6 +648,7 @@
if(blocksize != 0 && orig_zonesize < blocksize)
goto out_bad_size;

+ /* RDE: convert log zone size to bit shift */
switch (s -> u.isofs_sb.s_log_zone_size)
{ case 512: s -> u.isofs_sb.s_log_zone_size = 9; break;
case 1024: s -> u.isofs_sb.s_log_zone_size = 10; break;
@@ -657,21 +669,46 @@

/* RDE: data zone now byte offset! */

- s->u.isofs_sb.s_firstdatazone = ((isonum_733 (rootp->extent) +
- isonum_711 (rootp->ext_attr_length))
- << s -> u.isofs_sb.s_log_zone_size);
+ first_data_zone = ((isonum_733 (rootp->extent) +
+ isonum_711 (rootp->ext_attr_length))
+ << s -> u.isofs_sb.s_log_zone_size);
+ s->u.isofs_sb.s_firstdatazone = first_data_zone;
#ifndef BEQUIET
- printk(KERN_DEBUG "Max size:%ld Log zone size:%ld\n",
+ printk("Max size:%ld Log zone size:%ld\n",
s->u.isofs_sb.s_max_size,
1UL << s->u.isofs_sb.s_log_zone_size);
- printk(KERN_DEBUG "First datazone:%ld Root inode number %d\n",
+ printk("First datazone:%ld Root inode number:%ld\n",
s->u.isofs_sb.s_firstdatazone >> s -> u.isofs_sb.s_log_zone_size,
s->u.isofs_sb.s_firstdatazone);
if(high_sierra)
- printk(KERN_DEBUG "Disc in High Sierra format.\n");
+ printk("Disc in High Sierra format.\n");
#endif

/*
+ * If the Joliet level is set, we _may_ decide to use the
+ * secondary descriptor, but can't be sure until after we
+ * read the root inode. But before reading the root inode
+ * we may need to change the device blocksize, and would
+ * rather release the old buffer first. So, we cache the
+ * first_data_zone value from the secondary descriptor.
+ */
+ if (joliet_level) {
+ pri = (struct iso_primary_descriptor *) sec;
+ rootp = (struct iso_directory_record *)
+ pri->root_directory_record;
+ first_data_zone = ((isonum_733 (rootp->extent) +
+ isonum_711 (rootp->ext_attr_length))
+ << s -> u.isofs_sb.s_log_zone_size);
+ }
+
+ /*
+ * We're all done using the volume descriptor, and may need
+ * to change the device blocksize, so release the buffer now.
+ */
+printk("isofs_read_super: releasing bh=%p\n", bh);
+ brelse(bh);
+
+ /*
* Force the blocksize to 512 for 512 byte sectors. The file
* read primitives really get it wrong in a bad way if we don't
* do this.
@@ -688,22 +725,14 @@
* entries. By forcing the blocksize in this way, we ensure
* that we will never be required to do this.
*/
- if( orig_zonesize != opt.blocksize )
- {
- opt.blocksize = orig_zonesize;
- blocksize_bits = 0;
- {
- int i = opt.blocksize;
- while (i != 1){
- blocksize_bits++;
- i >>=1;
- }
- }
- set_blocksize(dev, opt.blocksize);
+ if ( orig_zonesize != opt.blocksize ) {
+ set_blocksize(dev, orig_zonesize);
#ifndef BEQUIET
- printk(KERN_DEBUG "Forcing new log zone size:%d\n", opt.blocksize);
+ printk("ISOFS: Forcing new log zone size:%d\n", orig_zonesize);
#endif
- }
+ }
+ s->s_blocksize = orig_zonesize;
+ s->s_blocksize_bits = s -> u.isofs_sb.s_log_zone_size;

s->u.isofs_sb.s_nls_iocharset = NULL;

@@ -732,8 +761,14 @@
* as suid, so we merely allow them to set the default permissions.
*/
s->u.isofs_sb.s_mode = opt.mode & 0777;
- s->s_blocksize = opt.blocksize;
- s->s_blocksize_bits = blocksize_bits;
+
+ /*
+ * Read the root inode, which _may_ result in changing
+ * the s_rock flag. Once we have the final s_rock value,
+ * we then decide whether to use the Joliet descriptor.
+ */
+printk("isofs_read_super: reading root inode=%ld\n",
+s->u.isofs_sb.s_firstdatazone);
inode = iget(s, s->u.isofs_sb.s_firstdatazone);

/*
@@ -744,21 +779,16 @@
* CD with Unicode names. Until someone sees such a beast, it
* will not be supported.
*/
- if (opt.rock == 'y' && s->u.isofs_sb.s_rock == 1) {
+ if (s->u.isofs_sb.s_rock == 1) {
joliet_level = 0;
- }
- if (joliet_level) {
- iput(inode);
- pri = (struct iso_primary_descriptor *) sec;
- rootp = (struct iso_directory_record *)
- pri->root_directory_record;
- s->u.isofs_sb.s_firstdatazone =
- ((isonum_733 (rootp->extent) +
- isonum_711 (rootp->ext_attr_length))
- << s -> u.isofs_sb.s_log_zone_size);
- inode = iget(s, s->u.isofs_sb.s_firstdatazone);
+ } else if (joliet_level) {
s->u.isofs_sb.s_rock = 0;
- opt.rock = 'n';
+ if (s->u.isofs_sb.s_firstdatazone != first_data_zone) {
+ s->u.isofs_sb.s_firstdatazone = first_data_zone;
+ iput(inode);
+ inode = iget(s, s->u.isofs_sb.s_firstdatazone);
+ printk("ISOFS: changed to secondary root\n");
+ }
}

if (opt.check == 'u') {
@@ -766,7 +796,11 @@
if (joliet_level) opt.check = 'r';
else opt.check = 's';
}
+ s->u.isofs_sb.s_joliet_level = joliet_level;

+ /* get the root dentry */
+ if (!inode)
+ goto out_no_root;
s->s_root = d_alloc_root(inode, NULL);
if (!(s->s_root))
goto out_no_root;
@@ -775,11 +809,14 @@
if (opt.check == 'r') table++;
s->s_root->d_op = &isofs_dentry_ops[table];

+printk("isofs_read_super: checking disk change\n");
if(!check_disk_change(dev)) {
- brelse(bh);
+ /* turn off ide-cd debugging */
+ ide_cd_debug = 0;
unlock_super(s);
return s;
}
+printk("isofs_read_super: disk change failed!\n");
/*
* Disk changed? Free the root dentry and clean up ...
*/
@@ -790,8 +827,14 @@
* Display error message
*/
out_no_root:
- printk(KERN_ERR "isofs_read_super: get root inode failed\n");
- goto out_iput;
+ printk(KERN_WARNING "isofs_read_super: get root inode failed\n");
+ iput(inode);
+out_freechar:
+#ifdef CONFIG_JOLIET
+ if (s->u.isofs_sb.s_nls_iocharset)
+ unload_nls(s->u.isofs_sb.s_nls_iocharset);
+#endif
+ goto out_unlock;
out_bad_zone_size:
printk(KERN_WARNING "Bad logical zone size %ld\n",
s->u.isofs_sb.s_log_zone_size);
@@ -818,16 +861,11 @@
/*
* Cascaded error cleanup to ensure all resources are freed.
*/
-out_iput:
- iput(inode);
-out_freechar:
-#ifdef CONFIG_JOLIET
- if (s->u.isofs_sb.s_nls_iocharset)
- unload_nls(s->u.isofs_sb.s_nls_iocharset);
-#endif
out_freebh:
brelse(bh);
out_unlock:
+ /* turn off ide-cd debugging */
+ ide_cd_debug = 0;
s->s_dev = 0;
unlock_super(s);
MOD_DEC_USE_COUNT;
@@ -1031,9 +1069,10 @@
int i;

block = inode->i_ino >> ISOFS_BUFFER_BITS(inode);
- if (!(bh=bread(inode->i_dev,block, bufsize))) {
- printk("unable to read i-node block");
- goto fail;
+ bh = bread(inode->i_dev, block, bufsize);
+ if (!bh) {
+ printk(KERN_WARNING "ISOFS: unable to read i-node block\n");
+ goto fail;
}

pnt = ((unsigned char *) bh->b_data
@@ -1049,10 +1088,13 @@
easier to give 1 which tells find to
do it the hard way. */
} else {
- inode->i_mode = inode->i_sb->u.isofs_sb.s_mode; /* Everybody gets to read the file. */
+ /* Everybody gets to read the file. */
+ inode->i_mode = inode->i_sb->u.isofs_sb.s_mode;
inode->i_nlink = 1;
inode->i_mode |= S_IFREG;
-/* If there are no periods in the name, then set the execute permission bit */
+ /* If there are no periods in the name,
+ * then set the execute permission bit
+ */
for(i=0; i< raw_inode->name_len[0]; i++)
if(raw_inode->name[i]=='.' || raw_inode->name[i]==';')
break;
@@ -1173,6 +1215,7 @@
init_fifo(inode);
}
return;
+
fail:
/* With a data error we return this information */
inode->i_mtime = inode->i_atime = inode->i_ctime = 0;
--- linux-2.1.121/drivers/block/ide-cd.c.old Tue Sep 1 21:27:13 1998
+++ linux-2.1.121/drivers/block/ide-cd.c Mon Sep 14 15:45:28 1998
@@ -240,6 +240,9 @@
#include "ide.h"
#include "ide-cd.h"

+/* temporary for debugging */
+#include <linux/utsname.h>
+#define ide_cd_debug (system_utsname.sysname[64])

/****************************************************************************
* Generic packet command support and error handling routines.
@@ -634,8 +637,13 @@
/* Wait for the controller to be idle. */
if (ide_wait_stat (drive, 0, BUSY_STAT, WAIT_READY)) return 1;

- if (info->dma)
+ if (info->dma) {
+if (ide_cd_debug)
+printk("cdrom_start_packet_command: dma requested\n");
info->dma = !HWIF(drive)->dmaproc(ide_dma_read, drive);
+if (ide_cd_debug)
+printk("cdrom_start_packet_command: dma set to %d\n", info->dma);
+ }

/* Set up the controller registers. */
OUT_BYTE (info->dma, IDE_FEATURE_REG);
@@ -646,8 +654,11 @@
OUT_BYTE (xferlen >> 8 , IDE_HCYL_REG);
OUT_BYTE (drive->ctl, IDE_CONTROL_REG);

- if (info->dma)
+ if (info->dma) {
+if (ide_cd_debug)
+printk("cdrom_start_packet_command: begin dma\n");
(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+ }

if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
ide_set_handler (drive, handler, WAIT_CMD);
@@ -794,16 +805,20 @@
*/
static void cdrom_read_intr (ide_drive_t *drive)
{
- int stat;
- int ireason, len, sectors_to_transfer, nskip;
struct cdrom_info *info = drive->driver_data;
+ struct request *rq = HWGROUP(drive)->rq;
int i, dma = info->dma, dma_error = 0;
+ int stat;
+ int ireason, len, sectors_to_transfer, nskip;

- struct request *rq = HWGROUP(drive)->rq;
+if (ide_cd_debug)
+printk("cdrom_read_intr: dma is %d\n", dma);

/* Check for errors. */
if (dma) {
info->dma = 0;
+if (ide_cd_debug)
+printk("cdrom_read_intr: dma set to 0\n");
if ((dma_error = HWIF(drive)->dmaproc(ide_dma_end, drive)))
HWIF(drive)->dmaproc(ide_dma_off, drive);
}
@@ -1081,6 +1096,8 @@
struct cdrom_info *info = drive->driver_data;

info->dma = 0;
+if (ide_cd_debug)
+printk("cdrom_start_seek: dma set to 0\n");
info->start_seek = jiffies;
cdrom_start_packet_command (drive, 0, cdrom_start_seek_continuation);
}
@@ -1093,6 +1110,7 @@
struct cdrom_info *info = drive->driver_data;
struct request *rq = HWGROUP(drive)->rq;
int minor = MINOR (rq->rq_dev);
+ int use_dma;

/* If the request is relative to a partition, fix it up to refer to the
absolute address. */
@@ -1113,10 +1131,12 @@
/* Clear the local sector buffer. */
info->nsectors_buffered = 0;

- if (drive->using_dma && (rq->sector % SECTORS_PER_FRAME == 0) && (rq->nr_sectors % SECTORS_PER_FRAME == 0))
- info->dma = 1;
- else
- info->dma = 0;
+ use_dma = (drive->using_dma &&
+ (rq->sector % SECTORS_PER_FRAME == 0) &&
+ (rq->nr_sectors % SECTORS_PER_FRAME == 0));
+ info->dma = use_dma;
+if (ide_cd_debug)
+printk("cdrom_start_read: dma set to %d\n", use_dma);

/* Start sending the read request to the drive. */
cdrom_start_packet_command (drive, 32768,
@@ -1264,12 +1284,14 @@

static void cdrom_do_packet_command (ide_drive_t *drive)
{
- int len;
+ struct cdrom_info *info = drive->driver_data;
struct request *rq = HWGROUP(drive)->rq;
struct packet_command *pc = (struct packet_command *)rq->buffer;
- struct cdrom_info *info = drive->driver_data;
+ int len;

info->dma = 0;
+if (ide_cd_debug)
+printk("cdrom_do_packet_command: dma set to 0\n");

len = pc->buflen;
if (len < 0) len = -len;

--------------6D4230752FBDF988D8346C86--

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/faq.html