--- /opt/kernel/linux-2.4.3/drivers/ide/ide-cd.c Fri Feb 9 20:30:23 2001 +++ drivers/ide/ide-cd.c Fri Apr 6 12:55:17 2001 @@ -977,8 +977,7 @@ /* If we've filled the present buffer but there's another chained buffer after it, move on. */ - if (rq->current_nr_sectors == 0 && - rq->nr_sectors > 0) + if (rq->current_nr_sectors == 0 && rq->nr_sectors) cdrom_end_request (1, drive); /* If the buffers are full, cache the rest of the data in our @@ -1192,6 +1191,55 @@ return cdrom_start_packet_command (drive, 0, cdrom_start_seek_continuation); } +static inline int cdrom_merge_requests(struct request *rq, struct request *nxt) +{ + int ret = 1; + + /* + * partitions not really working, but better check anyway... + */ + if (rq->cmd == nxt->cmd && rq->rq_dev == nxt->rq_dev) { + rq->nr_sectors += nxt->nr_sectors; + rq->hard_nr_sectors += nxt->nr_sectors; + rq->bhtail->b_reqnext = nxt->bh; + rq->bhtail = nxt->bhtail; + list_del(&nxt->queue); + blkdev_release_request(nxt); + ret = 0; + } + + return ret; +} + +/* + * the current request will always be the first one on the list + */ +static void cdrom_attempt_remerge(ide_drive_t *drive, struct request *rq) +{ + struct list_head *entry; + struct request *nxt; + unsigned long flags; + + spin_lock_irqsave(&io_request_lock, flags); + + while (1) { + entry = rq->queue.next; + if (entry == &drive->queue.queue_head) + break; + + nxt = blkdev_entry_to_request(entry); + if (rq->sector + rq->nr_sectors != nxt->sector) + break; + else if (rq->nr_sectors + nxt->nr_sectors > SECTORS_MAX) + break; + + if (cdrom_merge_requests(rq, nxt)) + break; + } + + spin_unlock_irqrestore(&io_request_lock, flags); +} + /* 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) @@ -1203,6 +1251,8 @@ rq->sector -= n; } rq->current_nr_sectors = rq->bh->b_size >> SECTOR_BITS; + rq->hard_nr_sectors = rq->nr_sectors; + rq->hard_sector = rq->sector; } /* @@ -1216,20 +1266,22 @@ /* If the request is relative to a partition, fix it up to refer to the absolute address. */ - if ((minor & PARTN_MASK) != 0) { + if (minor & PARTN_MASK) { rq->sector = block; minor &= ~PARTN_MASK; - rq->rq_dev = MKDEV (MAJOR(rq->rq_dev), minor); + rq->rq_dev = MKDEV(MAJOR(rq->rq_dev), minor); } /* We may be retrying this request after an error. Fix up any weirdness which might be present in the request packet. */ - restore_request (rq); + restore_request(rq); /* Satisfy whatever we can of this request from our cached sector. */ if (cdrom_read_from_buffer(drive)) return ide_stopped; + cdrom_attempt_remerge(drive, rq); + /* Clear the local sector buffer. */ info->nsectors_buffered = 0; @@ -1477,7 +1529,7 @@ static ide_startstop_t cdrom_write_intr(ide_drive_t *drive) { - int stat, ireason, len, sectors_to_transfer; + int stat, ireason, len, sectors_to_transfer, uptodate; struct cdrom_info *info = drive->driver_data; int i, dma_error = 0, dma = info->dma; ide_startstop_t startstop; @@ -1498,6 +1550,9 @@ return startstop; } + /* + * using dma, transfer is complete now + */ if (dma) { if (dma_error) return ide_error(drive, "dma error", stat); @@ -1519,12 +1574,13 @@ /* If we're not done writing, complain. * Otherwise, complete the command normally. */ + uptodate = 1; if (rq->current_nr_sectors > 0) { printk("%s: write_intr: data underrun (%ld blocks)\n", - drive->name, rq->current_nr_sectors); - cdrom_end_request(0, drive); - } else - cdrom_end_request(1, drive); + drive->name, rq->current_nr_sectors); + uptodate = 0; + } + cdrom_end_request(uptodate, drive); return ide_stopped; } @@ -1533,26 +1589,42 @@ if (cdrom_write_check_ireason(drive, len, ireason)) return ide_stopped; - /* The number of sectors we need to read from the drive. */ sectors_to_transfer = len / SECTOR_SIZE; - /* Now loop while we still have data to read from the drive. DMA - * transfers will already have been complete + /* + * now loop and write out the data */ while (sectors_to_transfer > 0) { - /* If we've filled the present buffer but there's another - chained buffer after it, move on. */ - if (rq->current_nr_sectors == 0 && rq->nr_sectors > 0) - cdrom_end_request(1, drive); - - atapi_output_bytes(drive, rq->buffer, rq->current_nr_sectors); - rq->nr_sectors -= rq->current_nr_sectors; - rq->current_nr_sectors = 0; - rq->sector += rq->current_nr_sectors; - sectors_to_transfer -= rq->current_nr_sectors; + int this_transfer; + + if (!rq->current_nr_sectors) { + printk("ide-cd: write_intr: oops\n"); + break; + } + + /* + * Figure out how many sectors we can transfer + */ + this_transfer = MIN(sectors_to_transfer,rq->current_nr_sectors); + + while (this_transfer > 0) { + atapi_output_bytes(drive, rq->buffer, SECTOR_SIZE); + rq->buffer += SECTOR_SIZE; + --rq->nr_sectors; + --rq->current_nr_sectors; + ++rq->sector; + --this_transfer; + --sectors_to_transfer; + } + + /* + * current buffer complete, move on + */ + if (rq->current_nr_sectors == 0 && rq->nr_sectors) + cdrom_end_request (1, drive); } - /* arm handler */ + /* re-arm handler */ ide_set_handler(drive, &cdrom_write_intr, 5 * WAIT_CMD, NULL); return ide_started; } @@ -1583,10 +1655,24 @@ return cdrom_transfer_packet_command(drive, &pc, cdrom_write_intr); } -static ide_startstop_t cdrom_start_write(ide_drive_t *drive) +static ide_startstop_t cdrom_start_write(ide_drive_t *drive, struct request *rq) { struct cdrom_info *info = drive->driver_data; + /* + * for dvd-ram and such media, it's a really big deal to get + * big writes all the time. so scour the queue and attempt to + * remerge requests, often the plugging will not have had time + * to do this properly + */ + if (rq->nr_sectors & 3) { + cdrom_attempt_remerge(drive, rq); + if (rq->nr_sectors & 3) { + cdrom_end_request(0, drive); + return ide_stopped; + } + } + info->nsectors_buffered = 0; /* use dma, if possible. we don't need to check more, since we @@ -1629,7 +1715,7 @@ if (rq->cmd == READ) action = cdrom_start_read(drive, block); else - action = cdrom_start_write(drive); + action = cdrom_start_write(drive, rq); } info->last_block = block; return action; --- /opt/kernel/linux-2.4.3/drivers/ide/ide-cd.h Tue Mar 27 01:49:15 2001 +++ drivers/ide/ide-cd.h Fri Apr 6 12:23:16 2001 @@ -37,11 +37,12 @@ /************************************************************************/ -#define SECTOR_SIZE 512 #define SECTOR_BITS 9 -#define SECTORS_PER_FRAME (CD_FRAMESIZE / SECTOR_SIZE) +#define SECTOR_SIZE (1 << SECTOR_BITS) +#define SECTORS_PER_FRAME (CD_FRAMESIZE >> SECTOR_BITS) #define SECTOR_BUFFER_SIZE (CD_FRAMESIZE * 32) -#define SECTORS_BUFFER (SECTOR_BUFFER_SIZE / SECTOR_SIZE) +#define SECTORS_BUFFER (SECTOR_BUFFER_SIZE >> SECTOR_BITS) +#define SECTORS_MAX (131072 >> SECTOR_BITS) #define BLOCKS_PER_FRAME (CD_FRAMESIZE / BLOCK_SIZE)