[PATCH]: CD-ROM fixes for 2.3.23-pre3

Jens Axboe (axboe@image.dk)
Tue, 19 Oct 1999 22:06:09 +0200


--WIyZ46R2i8wDzkSu
Content-Type: text/plain; charset=us-ascii

Hi all,

It seems that some of my CD-ROM stuff inadvertently got included
in 2.3.23-pre2/2. This is rather unfortunate because it was
definately not ready for "general consumption", partly
because some of it was targeted at providing writeable
support for CD-RW and not finished in any way. Here's an
update against 2.3.23-pre3 that attempts to recitify
the situation.

-- 
*  Jens Axboe <axboe@image.dk>
*  Linux CD-ROM Maintainer
*  http://www.kernel.dk

--WIyZ46R2i8wDzkSu Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="oct19.diff"

diff -ur --exclude-from /home/axboe/cdrom/exclude-from /tmp/linux-2.3.23/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c --- /tmp/linux-2.3.23/drivers/block/ide-cd.c Tue Oct 19 21:36:17 1999 +++ linux/drivers/block/ide-cd.c Tue Oct 19 21:55:38 1999 @@ -339,14 +339,15 @@ failed_command->c[0] == GPCMD_READ_SUBCHANNEL) return; } + if (reqbuf->error_code == 0x70 && reqbuf->sense_key == 0x02 && ((reqbuf->asc == 0x3a && reqbuf->ascq == 0x00) || (reqbuf->asc == 0x04 && reqbuf->ascq == 0x01))) { /* * Suppress the following errors: - * "Medium not present", and "in progress of becoming ready", - * to keep the noise level down to a dull roar. + * "Medium not present", "in progress of becoming ready", + * and "writing" to keep the noise level down to a dull roar. */ return; } @@ -431,6 +432,19 @@ printk ("\"\n"); } + /* The SKSV bit specifies validity of the sense_key_specific + * in the next two commands. It is bit 7 of the first byte. + * In the case of NOT_READY, if SKSV is set the drive can + * give us nice ETA readings. + */ + if (reqbuf->sense_key == NOT_READY && + (reqbuf->sense_key_specific[0] & 0x80)) { + int progress = (reqbuf->sense_key_specific[1] << 8 | + reqbuf->sense_key_specific[2]) * 100; + printk(" Command is %02d%% complete\n", progress / 0xffff); + + } + if (reqbuf->sense_key == ILLEGAL_REQUEST && (reqbuf->sense_key_specific[0] & 0x80) != 0) { printk (" Error in %s byte %d", @@ -466,21 +480,6 @@ #endif /* not VERBOSE_IDE_CD_ERRORS */ } - -/* Fix up a possibly partially-processed request so that we can - start it over entirely, or even put it back on the request queue. */ -static void restore_request (struct request *rq) -{ - if (rq->buffer != rq->bh->b_data) { - int n = (rq->buffer - rq->bh->b_data) / SECTOR_SIZE; - rq->buffer = rq->bh->b_data; - rq->nr_sectors += n; - rq->sector -= n; - } - rq->current_nr_sectors = rq->bh->b_size >> SECTOR_BITS; -} - - static void cdrom_queue_request_sense (ide_drive_t *drive, struct semaphore *sem, struct atapi_request_sense *reqbuf, @@ -533,10 +532,8 @@ struct packet_command *pc = (struct packet_command *) rq->buffer; cdrom_analyze_sense_data (drive, - (struct atapi_request_sense *) - (pc->buffer - pc->c[4]), - (struct packet_command *) - pc->sense_data); + (struct atapi_request_sense *) (pc->buffer - pc->c[4]), + (struct packet_command *) pc->sense_data); } if (rq->cmd == READ && !rq->current_nr_sectors) uptodate = 1; @@ -680,7 +677,7 @@ struct cdrom_info *info = drive->driver_data; /* Wait for the controller to be idle. */ - if (ide_wait_stat (drive, 0, BUSY_STAT, WAIT_READY)) return 1; + if (ide_wait_stat(drive, 0, BUSY_STAT, WAIT_READY)) return 1; if (info->dma) info->dma = !HWIF(drive)->dmaproc(ide_dma_read, drive); @@ -719,9 +716,10 @@ unsigned char *cmd_buf, int cmd_len, ide_handler_t *handler) { - /* set timeout to an hour */ + /* don't timeout for blank and format commands. they may take + * a _very_ long time. */ if (cmd_buf[0] == GPCMD_BLANK || cmd_buf[0] == GPCMD_FORMAT_UNIT) - drive->timeout = 3600*HZ; + drive->timeout = 0; if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) { /* Here we should have been called after receiving an interrupt @@ -774,13 +772,12 @@ /* If we don't yet have a sector buffer, try to allocate one. If we can't get one atomically, it's not fatal -- we'll just throw the data away rather than caching it. */ - if (info->sector_buffer == NULL) { - info->sector_buffer = (char *) kmalloc (SECTOR_BUFFER_SIZE, - GFP_ATOMIC); + if (info->buffer == NULL) { + info->buffer = (char *) kmalloc(SECTOR_BUFFER_SIZE, GFP_ATOMIC); /* If we couldn't get a buffer, don't try to buffer anything... */ - if (info->sector_buffer == NULL) + if (info->buffer == NULL) sectors_to_buffer = 0; } @@ -789,7 +786,7 @@ info->sector_buffered = sector; /* Read the data into the buffer. */ - dest = info->sector_buffer + info->nsectors_buffered * SECTOR_SIZE; + dest = info->buffer + info->nsectors_buffered * SECTOR_SIZE; while (sectors_to_buffer > 0) { atapi_input_bytes (drive, dest, SECTOR_SIZE); --sectors_to_buffer; @@ -806,7 +803,6 @@ } } - /* * Check the contents of the interrupt reason register from the cdrom * and attempt to recover if there are problems. Returns 0 if everything's @@ -921,8 +917,7 @@ /* First, figure out if we need to bit-bucket any of the leading sectors. */ - nskip = MIN ((int)(rq->current_nr_sectors - - (rq->bh->b_size >> SECTOR_BITS)), + nskip = MIN ((int)(rq->current_nr_sectors - (rq->bh->b_size >> SECTOR_BITS)), sectors_to_transfer); while (nskip > 0) { @@ -948,8 +943,7 @@ /* If the buffers are full, cache the rest of the data in our internal buffer. */ if (rq->current_nr_sectors == 0) { - cdrom_buffer_sectors (drive, - rq->sector, sectors_to_transfer); + cdrom_buffer_sectors(drive, rq->sector, sectors_to_transfer); sectors_to_transfer = 0; } else { /* Transfer data to the buffers. @@ -961,8 +955,7 @@ /* Read this_transfer sectors into the current buffer. */ while (this_transfer > 0) { - atapi_input_bytes (drive, - rq->buffer, SECTOR_SIZE); + atapi_input_bytes(drive, rq->buffer, SECTOR_SIZE); rq->buffer += SECTOR_SIZE; --rq->nr_sectors; --rq->current_nr_sectors; @@ -975,10 +968,9 @@ /* Done moving data! Wait for another interrupt. */ - ide_set_handler (drive, &cdrom_read_intr); + ide_set_handler(drive, &cdrom_read_intr); } - /* * Try to satisfy some of the current read request from our cached data. * Returns nonzero if the request has been completed, zero otherwise. @@ -989,7 +981,7 @@ struct request *rq = HWGROUP(drive)->rq; /* Can't do anything if there's no buffer. */ - if (info->sector_buffer == NULL) return 0; + if (info->buffer == NULL) return 0; /* Loop while this request needs data and the next block is present in our cache. */ @@ -1000,7 +992,7 @@ cdrom_end_request (1, drive); memcpy (rq->buffer, - info->sector_buffer + + info->buffer + (rq->sector - info->sector_buffered) * SECTOR_SIZE, SECTOR_SIZE); rq->buffer += SECTOR_SIZE; @@ -1063,14 +1055,13 @@ nskip = (sector % SECTORS_PER_FRAME); if (nskip > 0) { /* Sanity check... */ - if (rq->current_nr_sectors != - (rq->bh->b_size >> SECTOR_BITS)) { - printk ("%s: cdrom_start_read_continuation: buffer botch (%ld)\n", + if (rq->current_nr_sectors != (rq->bh->b_size >> SECTOR_BITS) && + (rq->sector % CD_FRAMESIZE != 0)) { + printk ("%s: cdrom_start_read_continuation: buffer botch (%lu)\n", drive->name, rq->current_nr_sectors); cdrom_end_request (0, drive); return; } - sector -= nskip; nsect += nskip; rq->current_nr_sectors += nskip; @@ -1091,16 +1082,17 @@ pc.c[0] = GPCMD_READ_10; pc.c[7] = (nframes >> 8); pc.c[8] = (nframes & 0xff); - put_unaligned(cpu_to_be32(frame), (unsigned int *) &pc.c[2]); + put_unaligned(htonl (frame), (unsigned int *) &pc.c[2]); /* Send the command to the drive and return. */ (void) cdrom_transfer_packet_command (drive, pc.c, sizeof (pc.c), &cdrom_read_intr); } + #define IDECD_SEEK_THRESHOLD (1000) /* 1000 blocks */ -#define IDECD_SEEK_TIMER (2 * WAIT_MIN_SLEEP) /* 40 ms */ -#define IDECD_SEEK_TIMEOUT WAIT_CMD /* 10 sec */ +#define IDECD_SEEK_TIMER (5 * WAIT_MIN_SLEEP) /* 100 ms */ +#define IDECD_SEEK_TIMEOUT WAIT_CMD /* 10 sec */ static void cdrom_seek_intr (ide_drive_t *drive) { @@ -1114,7 +1106,7 @@ if (retry && jiffies - info->start_seek > IDECD_SEEK_TIMER) { if (--retry == 0) { - printk ("%s: disabled DSC seek overlap\n", drive->name); + printk("%s: disabled DSC seek overlap\n", drive->name); drive->dsc_overlap = 0; } } @@ -1147,6 +1139,19 @@ cdrom_start_packet_command (drive, 0, cdrom_start_seek_continuation); } +/* Fix up a possibly partially-processed request so that we can + start it over entirely, or even put it back on the request queue. */ +static void restore_request (struct request *rq) +{ + if (rq->buffer != rq->bh->b_data) { + int n = (rq->buffer - rq->bh->b_data) / SECTOR_SIZE; + rq->buffer = rq->bh->b_data; + rq->nr_sectors += n; + rq->sector -= n; + } + rq->current_nr_sectors = rq->bh->b_size >> SECTOR_BITS; +} + /* * Start a read request from the CD-ROM. */ @@ -1169,23 +1174,22 @@ restore_request (rq); /* Satisfy whatever we can of this request from our cached sector. */ - if (cdrom_read_from_buffer (drive)) + if (cdrom_read_from_buffer(drive)) return; - /* 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)) + /* use dma, if possible. */ + if (drive->using_dma && (rq->sector % SECTORS_PER_FRAME == 0) && + (rq->nr_sectors % SECTORS_PER_FRAME == 0)) info->dma = 1; else info->dma = 0; /* Start sending the read request to the drive. */ - cdrom_start_packet_command (drive, 32768, - cdrom_start_read_continuation); + cdrom_start_packet_command(drive, 32768, cdrom_start_read_continuation); } - /**************************************************************************** * Execute all other packet commands. */ @@ -1362,7 +1366,7 @@ if (reqbuf->sense_key == UNIT_ATTENTION) cdrom_saw_media_change (drive); else if (reqbuf->sense_key == NOT_READY && - reqbuf->asc == 4) { + reqbuf->asc == 4 && reqbuf->ascq != 4) { /* The drive is in the process of loading a disk. Retry, but wait a little to give the drive time to complete the load. */ @@ -1405,10 +1409,10 @@ static void ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, unsigned long block) { + struct cdrom_info *info = drive->driver_data; + switch (rq->cmd) { case READ: { - struct cdrom_info *info = drive->driver_data; - if (CDROM_CONFIG_FLAGS(drive)->seeking) { unsigned long elpased = jiffies - info->start_seek; int stat = GET_STAT(); @@ -2095,12 +2099,16 @@ if (slot_nr == CDSL_CURRENT) { - struct atapi_request_sense my_reqbuf; - int stat = cdrom_check_status (drive, &my_reqbuf); - if (stat == 0 || my_reqbuf.sense_key == UNIT_ATTENTION) + struct atapi_request_sense sense; + int stat = cdrom_check_status (drive, &sense); + if (stat == 0 || sense.sense_key == UNIT_ATTENTION) + return CDS_DISC_OK; + + if (sense.sense_key == NOT_READY && sense.asc == 0x04 && + sense.ascq == 0x04) return CDS_DISC_OK; - if (my_reqbuf.sense_key == NOT_READY) { + if (sense.sense_key == NOT_READY) { /* ATAPI doesn't have anything that can help us decide whether the drive is really emtpy or the tray is just open. irk. */ @@ -2381,7 +2389,6 @@ ide_add_setting(drive, "dsc_overlap", SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->dsc_overlap, NULL); } - static int ide_cdrom_setup (ide_drive_t *drive) { @@ -2496,10 +2503,10 @@ } #endif /* not STANDARD_ATAPI */ - info->toc = NULL; - info->sector_buffer = NULL; - info->sector_buffered = 0; - info->nsectors_buffered = 0; + info->toc = NULL; + info->buffer = NULL; + info->sector_buffered = 0; + info->nsectors_buffered = 0; info->changer_info = NULL; info->last_block = 0; info->start_seek = 0; @@ -2562,8 +2569,8 @@ if (ide_unregister_subdriver (drive)) return 1; - if (info->sector_buffer != NULL) - kfree(info->sector_buffer); + if (info->buffer != NULL) + kfree(info->buffer); if (info->toc != NULL) kfree(info->toc); if (info->changer_info != NULL) diff -ur --exclude-from /home/axboe/cdrom/exclude-from /tmp/linux-2.3.23/drivers/block/ide-cd.h linux/drivers/block/ide-cd.h --- /tmp/linux-2.3.23/drivers/block/ide-cd.h Tue Oct 19 21:36:17 1999 +++ linux/drivers/block/ide-cd.h Tue Oct 19 21:49:49 1999 @@ -34,19 +34,13 @@ #define NO_DOOR_LOCKING 0 #endif - -/* Size of buffer to allocate, in blocks, for audio reads. */ - -#ifndef CDROM_NBLOCKS_BUFFER -#define CDROM_NBLOCKS_BUFFER 8 -#endif - - /************************************************************************/ -#define SECTOR_SIZE 512 -#define SECTOR_BITS 9 -#define SECTORS_PER_FRAME (CD_FRAMESIZE / SECTOR_SIZE) +#define SECTOR_SIZE 512 +#define SECTOR_BITS 9 +#define SECTORS_PER_FRAME (CD_FRAMESIZE / SECTOR_SIZE) +#define SECTOR_BUFFER_SIZE (CD_FRAMESIZE * 32) +#define SECTORS_BUFFER (SECTOR_BUFFER_SIZE / SECTOR_SIZE) #define MIN(a,b) ((a) < (b) ? (a) : (b)) @@ -84,7 +78,8 @@ __u8 seeking : 1; /* Seeking in progress */ __u8 audio_play : 1; /* can do audio related commands */ __u8 close_tray : 1; /* can close the tray */ - __u8 reserved : 4; + __u8 writing : 1; /* pseudo write in progress */ + __u8 reserved : 3; byte max_speed; /* Max speed of the drive */ }; #define CDROM_CONFIG_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->config_flags)) @@ -488,13 +483,11 @@ byte reserved2[3]; }; - struct atapi_changer_info { struct atapi_mechstat_header hdr; struct atapi_slot slots[0]; }; - /* Extra per-device info for cdrom drives. */ struct cdrom_info { @@ -503,17 +496,9 @@ struct atapi_toc *toc; - /* Sector buffer. If a read request wants only the first part - of a cdrom block, we cache the rest of the block here, - in the expectation that the data is going to be wanted soon. - SECTOR_BUFFERED is the number of the first buffered sector, - and NSECTORS_BUFFERED is the number of sectors in the buffer. - Before the buffer is allocated, we should have - SECTOR_BUFFER == NULL and NSECTORS_BUFFERED == 0. */ - - unsigned long sector_buffered; - unsigned long nsectors_buffered; - char *sector_buffer; + unsigned long sector_buffered; + unsigned long nsectors_buffered; + unsigned char *buffer; /* The result of the last successful request sense command on this device. */ @@ -534,10 +519,6 @@ struct cdrom_device_info devinfo; }; - -#define SECTOR_BUFFER_SIZE CD_FRAMESIZE - - /**************************************************************************** * Descriptions of ATAPI error codes. */ @@ -653,6 +634,7 @@ { 0x000013, "Play operation successfully completed" }, { 0x000014, "Play operation stopped due to error" }, { 0x000015, "No current audio status to return" }, + { 0x010c0a, "Write error - padding blocks added" }, { 0x011700, "Recovered data with no error correction applied" }, { 0x011701, "Recovered data with retries" }, { 0x011702, "Recovered data with positive head offset" }, @@ -669,6 +651,7 @@ { 0x015d01, "Failure prediction threshold exceeded - Predicted media failure" }, { 0x015dff, "Failure prediction threshold exceeded - False" }, + { 0x017301, "Power calibration area almost full" }, { 0x020400, "Logical unit not ready - cause not reportable" }, /* Following is misspelled in ATAPI 2.6, _and_ in Mt. Fuji */ { 0x020401, @@ -681,9 +664,35 @@ { 0x023a00, "Medium not present" }, { 0x025300, "Media load or eject failed" }, { 0x025700, "Unable to recover table of contents" }, + { 0x030300, "Peripheral device write fault" }, + { 0x030301, "No write current" }, + { 0x030302, "Excessive write errors" }, + { 0x030c00, "Write error" }, + { 0x030c01, "Write error - Recovered with auto reallocation" }, + { 0x030c02, "Write error - auto reallocation failed" }, + { 0x030c03, "Write error - recommend reassignment" }, + { 0x030c04, "Compression check miscompare error" }, + { 0x030c05, "Data expansion occurred during compress" }, + { 0x030c06, "Block not compressible" }, + { 0x030c07, "Write error - recovery needed" }, + { 0x030c08, "Write error - recovery failed" }, + { 0x030c09, "Write error - loss of streaming" }, { 0x031100, "Unrecovered read error" }, { 0x031106, "CIRC unrecovered error" }, { 0x033101, "Format command failed" }, + { 0x033200, "No defect spare location available" }, + { 0x033201, "Defect list update failure" }, + { 0x035100, "Erase failure" }, + { 0x037200, "Session fixation error" }, + { 0x037201, "Session fixation error writin lead-in" }, + { 0x037202, "Session fixation error writin lead-out" }, + { 0x037300, "CD control error" }, + { 0x037302, "Power calibration area is full" }, + { 0x037303, "Power calibration area error" }, + { 0x037304, "Program memory area / RMA update failure" }, + { 0x037305, "Program memory area / RMA is full" }, + { 0x037306, "Program memory area / RMA is (almost) full" }, + { 0x040200, "No seek complete" }, { 0x040300, "Write fault" }, { 0x040900, "Track following error" }, @@ -701,11 +710,15 @@ { 0x052000, "Invalid command operation code" }, { 0x052c00, "Command sequence error" }, { 0x052100, "Logical block address out of range" }, + { 0x052102, "Invalid address for write" }, { 0x052400, "Invalid field in command packet" }, { 0x052600, "Invalid field in parameter list" }, { 0x052601, "Parameter not supported" }, { 0x052602, "Parameter value invalid" }, { 0x052700, "Write protected media" }, + { 0x052c00, "Command sequence error" }, + { 0x052c03, "Current program area is not empty" }, + { 0x052c04, "Current program area is empty" }, { 0x053001, "Cannot read medium - unknown format" }, { 0x053002, "Cannot read medium - incompatible format" }, { 0x053900, "Saving parameters not supported" }, @@ -714,11 +727,15 @@ { 0x055500, "System resource failure" }, { 0x056300, "End of user area encountered on this track" }, { 0x056400, "Illegal mode for this track or incompatible medium" }, - { 0x056f00, - "Copy protection key exchange failure - Authentication failure" }, + { 0x056f00, "Copy protection key exchange failure - Authentication failure" }, { 0x056f01, "Copy protection key exchange failure - Key not present" }, - { 0x056f02, - "Copy protection key exchange failure - Key not established" }, + { 0x056f02, "Copy protection key exchange failure - Key not established" }, + { 0x056f03, "Read of scrambled sector without authentication" }, + { 0x056f04, "Media region code is mismatched to logical unit" }, + { 0x056f05, "Drive region must be permanent / region reset count error" }, + { 0x057203, "Session fixation error - incomplete track in session" }, + { 0x057204, "Empty or partially written reserved track" }, + { 0x057205, "No more RZONE reservations are allowed" }, { 0x05bf00, "Loss of streaming" }, { 0x062800, "Not ready to ready transition, medium may have changed" }, { 0x062900, "Power on, reset or hardware reset occurred" }, diff -ur --exclude-from /home/axboe/cdrom/exclude-from /tmp/linux-2.3.23/drivers/block/ide.c linux/drivers/block/ide.c --- /tmp/linux-2.3.23/drivers/block/ide.c Tue Oct 19 21:36:17 1999 +++ linux/drivers/block/ide.c Tue Oct 19 21:42:35 1999 @@ -498,6 +498,18 @@ } /* + * The below two are helpers used when modifying the drive timeout. + */ +static inline unsigned long set_timeout(ide_drive_t *drive, unsigned long timeout) +{ + unsigned long foo = drive->timeout; + drive->timeout = timeout; + return foo; +} + +#define restore_timeout(drive, old) (drive->timeout = old) + +/* * This should get invoked any time we exit the driver to * wait for an interrupt response from a drive. handler() points * at the appropriate code to handle the next interrupt, and a @@ -517,8 +529,11 @@ } #endif hwgroup->handler = handler; - hwgroup->timer.expires = jiffies + drive->timeout; - add_timer(&(hwgroup->timer)); + /* 0 means don't timeout */ + if (drive->timeout && !timer_pending(&hwgroup->timer)) { + hwgroup->timer.expires = jiffies + drive->timeout; + add_timer(&(hwgroup->timer)); + } spin_unlock_irqrestore(&hwgroup->spinlock, flags); } @@ -575,10 +590,9 @@ printk("%s: ATAPI reset complete\n", drive->name); } else { if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) { - old_timeout = drive->timeout; - drive->timeout = HZ / 20; + old_timeout = set_timeout(drive, HZ / 20); ide_set_handler (drive, &atapi_reset_pollfunc); - drive->timeout = old_timeout; + restore_timeout(drive, old_timeout); return; /* continue polling */ } hwgroup->poll_timeout = 0; /* end of polling */ @@ -604,10 +618,9 @@ if (!OK_STAT(tmp=GET_STAT(), 0, BUSY_STAT)) { if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) { - old_timeout = drive->timeout; - drive->timeout = HZ / 20; + old_timeout = set_timeout(drive, HZ / 20); ide_set_handler (drive, &reset_pollfunc); - drive->timeout = old_timeout; + restore_timeout(drive, old_timeout); return; /* continue polling */ } printk("%s: reset timed-out, status=0x%02x\n", hwif->name, tmp); @@ -687,10 +700,9 @@ udelay (20); OUT_BYTE (WIN_SRST, IDE_COMMAND_REG); hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; - old_timeout = drive->timeout; - drive->timeout = HZ / 20; + old_timeout = set_timeout(drive, HZ / 20); ide_set_handler (drive, &atapi_reset_pollfunc); - drive->timeout = old_timeout; + restore_timeout(drive, old_timeout); __restore_flags (flags); /* local CPU only */ return; } @@ -720,10 +732,9 @@ OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG); /* clear SRST, leave nIEN */ udelay(10); /* more than enough time */ hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; - old_timeout = drive->timeout; - drive->timeout = HZ / 20; + old_timeout = set_timeout(drive, HZ / 20); ide_set_handler (drive, &reset_pollfunc); - drive->timeout = old_timeout; + restore_timeout(drive, old_timeout); /* * Some weird controller like resetting themselves to a strange @@ -923,7 +934,6 @@ */ void ide_cmd(ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler) { - drive->timeout = WAIT_CMD; ide_set_handler (drive, handler); if (IDE_CONTROL_REG) OUT_BYTE(drive->ctl,IDE_CONTROL_REG); /* clear nIEN */ diff -ur --exclude-from /home/axboe/cdrom/exclude-from /tmp/linux-2.3.23/drivers/block/pdc4030.c linux/drivers/block/pdc4030.c --- /tmp/linux-2.3.23/drivers/block/pdc4030.c Tue Oct 19 21:36:17 1999 +++ linux/drivers/block/pdc4030.c Tue Oct 19 21:42:35 1999 @@ -396,7 +396,6 @@ if (GET_STAT() & BUSY_STAT) { if (time_before(jiffies, hwgroup->poll_timeout)) { - drive->timeout = 1; ide_set_handler(drive, &promise_complete_pollfunc); return; /* continue polling... */ } @@ -426,7 +425,6 @@ if (IN_BYTE(IDE_NSECTOR_REG) != 0) { if (time_before(jiffies, hwgroup->poll_timeout)) { - drive->timeout = 1; ide_set_handler (drive, &promise_write_pollfunc); return; /* continue polling... */ } @@ -441,7 +439,6 @@ */ ide_multwrite(drive, 4); hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; - drive->timeout = 1; ide_set_handler(drive, &promise_complete_pollfunc); #ifdef DEBUG_WRITE printk(KERN_DEBUG "%s: Done last 4 sectors - status = %02x\n", @@ -475,7 +472,6 @@ if (rq->nr_sectors > 4) { ide_multwrite(drive, rq->nr_sectors - 4); hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; - drive->timeout = 1; ide_set_handler (drive, &promise_write_pollfunc); } else { /* @@ -484,7 +480,6 @@ */ ide_multwrite(drive, rq->nr_sectors); hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; - drive->timeout = 1; ide_set_handler(drive, &promise_complete_pollfunc); #ifdef DEBUG_WRITE printk(KERN_DEBUG "%s: promise_write: <= 4 sectors, " diff -ur --exclude-from /home/axboe/cdrom/exclude-from /tmp/linux-2.3.23/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c --- /tmp/linux-2.3.23/drivers/cdrom/cdrom.c Tue Oct 19 21:36:17 1999 +++ linux/drivers/cdrom/cdrom.c Tue Oct 19 21:57:39 1999 @@ -308,8 +308,6 @@ */ #define ENSURE(call, bits) if (cdo->call == NULL) *change_capability &= ~(bits) -static int cdrom_setup_writemode(struct cdrom_device_info *cdi); - int register_cdrom(struct cdrom_device_info *cdi) { static char banner_printed = 0; @@ -357,9 +355,6 @@ cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name); cdi->next = topCdromPtr; topCdromPtr = cdi; - if (CDROM_CAN(CDC_CD_R) || CDROM_CAN(CDC_CD_RW) || CDROM_CAN(CDC_DVD_R)) - (void)cdrom_setup_writemode(cdi); - return 0; } #undef ENSURE @@ -415,6 +410,8 @@ return cdi; } +static int cdrom_setup_writemode(struct cdrom_device_info *cdi); + /* We use the open-option O_NONBLOCK to indicate that the * purpose of opening is only for subsequent ioctl() calls; no device * integrity checks are performed. @@ -426,22 +423,31 @@ static int cdrom_open(struct inode *ip, struct file *fp) { + struct cdrom_device_info *cdi; kdev_t dev = ip->i_rdev; - struct cdrom_device_info *cdi = cdrom_find_device(dev); - int purpose = !!(fp->f_flags & O_NONBLOCK); - int ret=0; + int ret; cdinfo(CD_OPEN, "entering cdrom_open\n"); - if (cdi == NULL) + if ((cdi = cdrom_find_device(dev)) == NULL) return -ENODEV; - if (fp->f_mode & FMODE_WRITE) - return -EROFS; - purpose = purpose || !(cdi->options & CDO_USE_FFLAGS); - if (purpose) - ret = cdi->ops->open(cdi, purpose); + + /* just CD-RW for now. DVD-RW will come soon, CD-R and DVD-R + * need to be handled differently. */ + if ((fp->f_mode & FMODE_WRITE) && !CDROM_CAN(CDC_CD_RW)) + return -EROFS; + + /* if this was a O_NONBLOCK open and we should honor the flags, + * do a quick open without drive/disc integrity checks. */ + if ((fp->f_flags & O_NONBLOCK) && (cdi->options & CDO_USE_FFLAGS)) + ret = cdi->ops->open(cdi, 1); else ret = open_for_data(cdi); + if (!ret) cdi->use_count++; + + if (fp->f_mode & FMODE_WRITE && !cdi->write.writeable) + cdi->write.writeable = !cdrom_setup_writemode(cdi); + cdinfo(CD_OPEN, "Use count for \"/dev/%s\" now %d\n", cdi->name, cdi->use_count); /* Do this on open. Don't wait for mount, because they might not be mounting, but opening with O_NONBLOCK */ @@ -536,7 +542,7 @@ if (CDROM_CAN(CDC_LOCK) && cdi->options & CDO_LOCK) { cdo->lock_door(cdi, 1); cdinfo(CD_OPEN, "door locked.\n"); - } + } cdinfo(CD_OPEN, "device opened successfully.\n"); return ret; @@ -627,7 +633,7 @@ if (cdi->use_count > 0) cdi->use_count--; if (cdi->use_count == 0) cdinfo(CD_CLOSE, "Use count for \"/dev/%s\" now zero\n", cdi->name); - if (cdi->use_count == 0 && /* last process that closes dev*/ + if (cdi->use_count == 0 && cdo->capability & CDC_LOCK && !keeplocked) { cdinfo(CD_CLOSE, "Unlocking door!\n"); cdo->lock_door(cdi, 0); @@ -2168,6 +2174,28 @@ } } +/* return the buffer size of writeable drives */ +static int cdrom_read_buffer_capacity(struct cdrom_device_info *cdi) +{ + struct cdrom_device_ops *cdo = cdi->ops; + struct cdrom_generic_command cgc; + struct { + unsigned int pad; + unsigned int buffer_size; + unsigned int buffer_free; + } buf; + int ret; + + init_cdrom_command(&cgc, &buf, 12); + cgc.cmd[0] = 0x5c; + cgc.cmd[8] = 12; + + if ((ret = cdo->generic_packet(cdi, &cgc))) + return ret; + + return be32_to_cpu(buf.buffer_size); +} + /* return 0 if succesful and the disc can be considered writeable. */ static int cdrom_setup_writemode(struct cdrom_device_info *cdi) { @@ -2180,6 +2208,7 @@ memset(&di, 0, sizeof(disc_information)); memset(&ti, 0, sizeof(track_information)); memset(&wp, 0, sizeof(write_param_page)); + memset(&cdi->write, 0, sizeof(struct cdrom_write_settings)); if ((ret = cdrom_get_disc_info(cdi->dev, &di))) return ret; @@ -2188,35 +2217,53 @@ if ((ret = cdrom_get_track_info(cdi->dev, last_track, 1, &ti))) return ret; + /* if the media is erasable, then it is either CD-RW or + * DVD-RW - use fixed packets for those. non-erasable media + * indicated CD-R or DVD-R media, use varible sized packets for + * those (where the packet size is a bit less than the buffer + * capacity of the drive. */ + if (di.erasable) { + cdi->write.fpacket = 1; + /* FIXME: DVD-RW is 16, should get the packet size instead */ + cdi->write.packet_size = 32; + } else { + int buf_size; + cdi->write.fpacket = 0; + buf_size = cdrom_read_buffer_capacity(cdi); + buf_size -= 100*1024; + cdi->write.packet_size = buf_size / CD_FRAMESIZE; + } + init_cdrom_command(&cgc, &wp, 0x3c); if ((ret = cdrom_mode_sense(cdi, &cgc, GPMODE_WRITE_PARMS_PAGE, 0))) return ret; /* sanity checks */ - if ((ti.damage && !ti.nwa_v) || ti.blank) + if ((ti.damage && !ti.nwa_v) || ti.blank) { + cdinfo(CD_WARNING, "can't write to this disc\n"); return 1; - - cdi->packet_size = wp.packet_size = be32_to_cpu(ti.fixed_packet_size); - cdi->nwa = ti.nwa_v ? be32_to_cpu(ti.next_writable) : 0; - wp.track_mode = ti.track_mode; - /* write_type 0 == packet/incremental writing */ - wp.write_type = 0; - - /* MODE1 or MODE2 writing */ - switch (ti.data_mode) { - case 1: wp.data_block_type = 8; break; - case 2: wp.data_block_type = 13; break; - default: return 1; } + /* NWA is only for CD-R and DVD-R. -RW media is randomly + * writeable once it has been formatted. */ + cdi->write.nwa = ti.nwa_v ? be32_to_cpu(ti.next_writable) : 0; + + wp.fp = cdi->write.fpacket ? 1 : 0; + wp.track_mode = 0; + wp.write_type = 0; + wp.data_block_type = 8; + wp.session_format = 0; + wp.multi_session = 3; + wp.audio_pause = cpu_to_be16(0x96); + wp.packet_size = cdi->write.fpacket ? cpu_to_be32(cdi->write.packet_size) : 0; + wp.track_mode = 5; /* should be ok with both CD and DVD */ + if ((ret = cdrom_mode_select(cdi, &cgc))) return ret; - printk("%s: writeable with %s packets of %lu in length", cdi->name, - wp.fp ? "fixed" : "variable", - (unsigned long)cdi->packet_size); - printk(", nwa = %lu\n", (unsigned long)cdi->nwa); - + cdinfo(CD_WARNING, "%s: writeable with %lu block %s packets\n", + cdi->name, cdi->write.packet_size, + cdi->write.fpacket ? "fixed" : "variable"); return 0; } @@ -2479,14 +2526,17 @@ initialized = 1; } +#endif /* endif CONFIG_SYSCTL */ + +#ifdef MODULE static void cdrom_sysctl_unregister(void) { +#ifdef CONFIG_SYSCTL unregister_sysctl_table(cdrom_sysctl_header); +#endif } -#endif /* endif CONFIG_SYSCTL */ -#ifdef MODULE int init_module(void) { #ifdef CONFIG_SYSCTL diff -ur --exclude-from /home/axboe/cdrom/exclude-from /tmp/linux-2.3.23/include/linux/cdrom.h linux/include/linux/cdrom.h --- /tmp/linux-2.3.23/include/linux/cdrom.h Tue Oct 19 21:36:17 1999 +++ linux/include/linux/cdrom.h Mon Oct 18 22:17:20 1999 @@ -273,6 +273,7 @@ unsigned char *buffer; unsigned int buflen; int stat; + void *reserved[4]; }; @@ -655,6 +656,14 @@ } dvd_authinfo; #ifdef __KERNEL__ + +struct cdrom_write_settings { + unsigned char fpacket; /* fixed/variable packets */ + unsigned long packet_size; /* write out this number of packets */ + unsigned long nwa; /* next writeable address */ + unsigned char writeable; /* cdrom is writeable */ +}; + /* Uniform cdrom data structures for cdrom.c */ struct cdrom_device_info { struct cdrom_device_ops *ops; /* link to device_ops */ @@ -673,8 +682,7 @@ /* per-device flags */ __u8 sanyo_slot : 2; /* Sanyo 3 CD changer support */ __u8 reserved : 6; /* not used yet */ - __u32 packet_size; /* write out this number of packets */ - __u32 nwa; /* next writeable address */ + struct cdrom_write_settings write; }; struct cdrom_device_ops {

--WIyZ46R2i8wDzkSu--

- 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/