diff -urN --exclude-from exclude-from linux-2.3.43-clean/Documentation/Configure.help linux-2.3.43/Documentation/Configure.help --- linux-2.3.43-clean/Documentation/Configure.help Fri Feb 11 00:53:35 2000 +++ linux-2.3.43/Documentation/Configure.help Fri Feb 11 00:52:38 2000 @@ -438,6 +438,23 @@ say M here and read Documentation/modules.txt. The module will be called ide-cd.o. + +Packet writing on CD/DVD media +CONFIG_CDROM_PACKET + If you have a CDROM drive that supports packet writing, say Y to + include preliminary support. It should work with any MMC/Mt Fuji + complain ATAPI or SCSI drive, which is just about any newer CD + writer. + + If you say Y here, you will be able to transparently write to CD-RW + and CD-R media. Writing is best used with the UDF file system, + so including that is recommended. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called packet.o. + Include IDE/ATAPI TAPE support CONFIG_BLK_DEV_IDETAPE If you have an IDE tape drive using the ATAPI protocol, say Y. diff -urN --exclude-from exclude-from linux-2.3.43-clean/drivers/block/Config.in linux-2.3.43/drivers/block/Config.in --- linux-2.3.43-clean/drivers/block/Config.in Thu Feb 10 06:41:50 2000 +++ linux-2.3.43/drivers/block/Config.in Thu Feb 10 06:38:28 2000 @@ -28,6 +28,9 @@ bool ' Use multi-mode by default' CONFIG_IDEDISK_MULTI_MODE fi dep_tristate ' Include IDE/ATAPI CDROM support' CONFIG_BLK_DEV_IDECD $CONFIG_BLK_DEV_IDE + if [ "$CONFIG_BLK_DEV_IDECD" != "n" ]; then + tristate ' Packet writing on CD/DVD media' CONFIG_CDROM_PACKET + fi dep_tristate ' Include IDE/ATAPI TAPE support' CONFIG_BLK_DEV_IDETAPE $CONFIG_BLK_DEV_IDE dep_tristate ' Include IDE/ATAPI FLOPPY support' CONFIG_BLK_DEV_IDEFLOPPY $CONFIG_BLK_DEV_IDE dep_tristate ' SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE diff -urN --exclude-from exclude-from linux-2.3.43-clean/drivers/block/Makefile linux-2.3.43/drivers/block/Makefile --- linux-2.3.43-clean/drivers/block/Makefile Tue Feb 8 22:59:16 2000 +++ linux-2.3.43/drivers/block/Makefile Tue Feb 8 22:16:24 2000 @@ -26,6 +26,14 @@ LX_OBJS := ll_rw_blk.o blkpg.o MX_OBJS := +ifeq ($(CONFIG_CDROM_PACKET),y) +LX_OBJS += packet.o +else + ifeq ($(CONFIG_CDROM_PACKET),m) + MX_OBJS += packet.o + endif +endif + ifeq ($(CONFIG_MAC_FLOPPY),y) L_OBJS += swim3.o endif diff -urN --exclude-from exclude-from linux-2.3.43-clean/drivers/block/ide-cd.c linux-2.3.43/drivers/block/ide-cd.c --- linux-2.3.43-clean/drivers/block/ide-cd.c Tue Feb 1 15:44:47 2000 +++ linux-2.3.43/drivers/block/ide-cd.c Fri Feb 11 07:11:14 2000 @@ -277,6 +277,7 @@ #define IDECD_VERSION "4.56" #include +#include #include #include #include @@ -313,29 +314,29 @@ static -void cdrom_analyze_sense_data (ide_drive_t *drive, struct request_sense *reqbuf, - struct packet_command *failed_command) +void cdrom_analyze_sense_data (ide_drive_t *drive, struct packet_command *pc, + struct request_sense *sense) { - if (reqbuf->sense_key == NOT_READY || - reqbuf->sense_key == UNIT_ATTENTION) { + if (sense->sense_key == NOT_READY || + sense->sense_key == UNIT_ATTENTION) { /* Make good and sure we've seen this potential media change. Some drives (i.e. Creative) fail to present the correct sense key in the error register. */ - cdrom_saw_media_change (drive); - + cdrom_saw_media_change(drive); + if (pc) + return; /* Don't print not ready or unit attention errors for READ_SUBCHANNEL. Workman (and probably other programs) uses this command to poll the drive, and we don't want to fill the syslog with useless errors. */ - if (failed_command && - failed_command->c[0] == GPCMD_READ_SUBCHANNEL) + if (pc->c[0] == GPCMD_READ_SUBCHANNEL || pc->c[0] == 0) return; } - if (reqbuf->error_code == 0x70 && reqbuf->sense_key == 0x02 - && ((reqbuf->asc == 0x3a && reqbuf->ascq == 0x00) || - (reqbuf->asc == 0x04 && reqbuf->ascq == 0x01))) + if (sense->error_code == 0x70 && sense->sense_key == 0x02 && + ((sense->asc == 0x3a && sense->ascq == 0x00) || + (sense->asc == 0x04 && sense->ascq == 0x01))) { /* * Suppress the following errors: @@ -352,30 +353,32 @@ char buf[80]; printk ("ATAPI device %s:\n", drive->name); - if (reqbuf->error_code==0x70) + if (sense->error_code==0x70) printk(" Error: "); - else if (reqbuf->error_code==0x71) + else if (sense->error_code==0x71) printk(" Deferred Error: "); + else if (sense->error_code == 0x7f) + printk(" Vendor-specific Error: "); else printk(" Unknown Error Type: "); - if ( reqbuf->sense_key < ARY_LEN (sense_key_texts)) - s = sense_key_texts[reqbuf->sense_key]; + if (sense->sense_key < ARY_LEN(sense_key_texts)) + s = sense_key_texts[sense->sense_key]; else s = "bad sense key!"; - printk ("%s -- (Sense key=0x%02x)\n", s, reqbuf->sense_key); + printk("%s -- (Sense key=0x%02x)\n", s, sense->sense_key); - if (reqbuf->asc == 0x40) { - sprintf (buf, "Diagnostic failure on component 0x%02x", - reqbuf->ascq); + if (sense->asc == 0x40) { + sprintf(buf, "Diagnostic failure on component 0x%02x", + sense->ascq); s = buf; } else { - int lo=0, mid, hi=ARY_LEN (sense_data_texts); - unsigned long key = (reqbuf->sense_key << 16); - key |= (reqbuf->asc << 8); - if ( ! (reqbuf->ascq >= 0x80 && reqbuf->ascq <= 0xdd) ) - key |= reqbuf->ascq; + int lo = 0, mid, hi = ARY_LEN(sense_data_texts); + unsigned long key = (sense->sense_key << 16); + key |= (sense->asc << 8); + if (!(sense->ascq >=0x80 && sense->ascq <=0xdd)) + key |= sense->ascq; s = NULL; while (hi > lo) { @@ -393,35 +396,35 @@ } if (s == NULL) { - if (reqbuf->asc > 0x80) + if (sense->asc > 0x80) s = "(vendor-specific error)"; else s = "(reserved error code)"; } printk (" %s -- (asc=0x%02x, ascq=0x%02x)\n", - s, reqbuf->asc, reqbuf->ascq); + s, sense->asc, sense->ascq); - if (failed_command != NULL) { + if (pc != NULL) { - int lo=0, mid, hi= ARY_LEN (packet_command_texts); + int lo = 0, mid, hi = ARY_LEN(packet_command_texts); s = NULL; while (hi > lo) { mid = (lo + hi) / 2; - if (packet_command_texts[mid].packet_command == failed_command->c[0]) { + if (packet_command_texts[mid].packet_command == pc->c[0]) { s = packet_command_texts[mid].text; break; } - else if (packet_command_texts[mid].packet_command > failed_command->c[0]) + else if (packet_command_texts[mid].packet_command > pc->c[0]) hi = mid; else lo = mid+1; } printk (" The failed \"%s\" packet command was: \n \"", s); - for (i=0; ic); i++) - printk ("%02x ", failed_command->c[i]); + for (i=0; i < sizeof(pc->c); i++) + printk ("%02x ", pc->c[i]); printk ("\"\n"); } @@ -430,21 +433,22 @@ * 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->sks[0] & 0x80)) { - int progress = (reqbuf->sks[1] << 8 | reqbuf->sks[2]) * 100; + if (sense->sense_key == NOT_READY && + (sense->sks[0] & 0x80)) { + int progress = (sense->sks[1] << 8 | sense->sks[2]) * 100; printk(" Command is %02d%% complete\n", progress / 0xffff); } - if (reqbuf->sense_key == ILLEGAL_REQUEST && - (reqbuf->sks[0] & 0x80) != 0) { - printk (" Error in %s byte %d", - (reqbuf->sks[0] & 0x40) != 0 ? + if (sense->sense_key == ILLEGAL_REQUEST && + (sense->sks[0] & 0x80) != 0) { + printk(" Error in %s byte %d", + (sense->sks[0] & 0x40) != 0 ? "command packet" : "command data", - (reqbuf->sks[1] << 8) + reqbuf->sks[2]); + (sense->sks[1] << 8) + sense->sks[2]); - if ((reqbuf->sks[0] & 0x40) != 0) - printk (" bit %d", reqbuf->sks[0] & 0x07); + if ((sense->sks[0] & 0x40) != 0) + printk(" bit %d", sense->sks[0] & 0x07); printk ("\n"); } @@ -455,63 +459,79 @@ /* Suppress printing unit attention and `in progress of becoming ready' errors when we're not being verbose. */ - if (reqbuf->sense_key == UNIT_ATTENTION || - (reqbuf->sense_key == NOT_READY && (reqbuf->asc == 4 || - reqbuf->asc == 0x3a))) + if (sense->sense_key == UNIT_ATTENTION || + (sense->sense_key == NOT_READY && (sense->asc == 4 || + sense->asc == 0x3a))) return; printk ("%s: error code: 0x%02x sense_key: 0x%02x asc: 0x%02x ascq: 0x%02x\n", - drive->name, - reqbuf->error_code, reqbuf->sense_key, - reqbuf->asc, reqbuf->ascq); + drive->name, sense->error_code, sense->sense_key, + sense->asc, sense->ascq); #endif /* not VERBOSE_IDE_CD_ERRORS */ } -static void cdrom_queue_request_sense (ide_drive_t *drive, - struct semaphore *sem, - struct packet_command *failed_command) +static void cdrom_queue_request_sense(ide_drive_t *drive, + struct semaphore *sem, + struct request_sense *sense, + struct packet_command *failed_cmd) { struct cdrom_info *info = drive->driver_data; struct request *rq; - struct packet_command *pc; + struct packet_command *pc = &info->request_sense_pc;; - /* Make up a new request to retrieve sense information. */ - pc = &info->request_sense_pc; - memset(pc, 0, sizeof (*pc)); + if (sense == NULL) + sense = &info->sense_data; + memset(pc, 0, sizeof(struct packet_command)); pc->c[0] = GPCMD_REQUEST_SENSE; - - /* just get the first 18 bytes of the sense info, there might not - * be more available */ pc->c[4] = pc->buflen = 18; - pc->buffer = (char *)&info->sense_data; - pc->sense_data = (struct request_sense *)failed_command; + pc->buffer = (char *) sense; + pc->sense = (struct request_sense *) failed_cmd; /* stuff the sense request in front of our current request */ rq = &info->request_sense_request; - ide_init_drive_cmd (rq); + ide_init_drive_cmd(rq); rq->cmd = REQUEST_SENSE_COMMAND; - rq->buffer = (char *)pc; + rq->buffer = (char *) pc; rq->sem = sem; - (void) ide_do_drive_cmd (drive, rq, ide_preempt); + (void) ide_do_drive_cmd(drive, rq, ide_preempt); } - static void cdrom_end_request (int uptodate, ide_drive_t *drive) { struct request *rq = HWGROUP(drive)->rq; if (rq->cmd == REQUEST_SENSE_COMMAND && uptodate) { - struct packet_command *pc = (struct packet_command *) - rq->buffer; - cdrom_analyze_sense_data (drive, - (struct request_sense *) (pc->buffer - pc->c[4]), - (struct packet_command *) pc->sense_data); + struct packet_command *pc = (struct packet_command *)rq->buffer; + cdrom_analyze_sense_data(drive, + (struct packet_command *) pc->sense, + (struct request_sense *) (pc->buffer - pc->c[4])); + } + if (rq->cmd == READ || rq->cmd == WRITE_PACKET) + if (!rq->current_nr_sectors) + uptodate = 1; + + if (rq->cmd == WRITE_PACKET && !uptodate) { + struct request *rq = HWGROUP(drive)->rq; + unsigned long flags; + int i; + +// printk("ending %s rq %lu\n", uptodate ? "good" : "dirty", rq->nr_sectors); + + spin_lock_irqsave(&io_request_lock, flags); + i = rq->nr_sectors; + for (i = rq->nr_sectors; i > 0; i -= rq->current_nr_sectors) + end_that_request_first(rq, 1, drive->name); + + HWGROUP(drive)->drive->queue.current_request = rq->next; + blk_dev[MAJOR(rq->rq_dev)].request_queue.current_request = NULL; + HWGROUP(drive)->rq = NULL; + end_that_request_last(rq); + spin_unlock_irqrestore(&io_request_lock, flags); + return; } - if (rq->cmd == READ && !rq->current_nr_sectors) - uptodate = 1; - ide_end_request (uptodate, HWGROUP(drive)); + ide_end_request(uptodate, HWGROUP(drive)); } @@ -522,7 +542,7 @@ { struct request *rq = HWGROUP(drive)->rq; int stat, cmd, err, sense_key; - struct packet_command *pc = (struct packet_command *) rq->buffer; + struct packet_command *pc; /* Check for errors. */ stat = GET_STAT(); @@ -545,7 +565,7 @@ /* We got an error trying to get sense info from the drive (probably while trying to recover from a former error). Just give up. */ - + pc = (struct packet_command *) rq->buffer; pc->stat = 1; cdrom_end_request (1, drive); *startstop = ide_error (drive, "request sense failure", stat); @@ -555,6 +575,7 @@ /* All other functions, except for READ. */ struct semaphore *sem = NULL; + pc = (struct packet_command *) rq->buffer; /* Check for tray open. */ if (sense_key == NOT_READY) { @@ -588,9 +609,10 @@ cdrom_end_request (1, drive); if ((stat & ERR_STAT) != 0) - cdrom_queue_request_sense(drive, sem, pc); + cdrom_queue_request_sense(drive, sem, pc->sense, + pc); } else { - /* Handle errors from READ requests. */ + /* Handle errors from READ and WRITE requests. */ if (sense_key == NOT_READY) { /* Tray open. */ @@ -627,7 +649,7 @@ /* If we got a CHECK_CONDITION status, queue a request sense command. */ if ((stat & ERR_STAT) != 0) - cdrom_queue_request_sense(drive, NULL, NULL); + cdrom_queue_request_sense(drive, NULL, NULL, NULL); } } @@ -642,11 +664,22 @@ struct packet_command *pc = (struct packet_command *) rq->buffer; unsigned long wait = 0; - /* blank and format can take an extremly long time to - * complete, if the IMMED bit was not set. + /* + * Some commands are *slow* and normally take a long time to + * complete. Usually we can use the ATAPI "disconnect" to bypass + * this, but not all commands/drives support that. Let + * ide_timer_expiry keep polling us for these. */ - if (pc->c[0] == GPCMD_BLANK || pc->c[0] == GPCMD_FORMAT_UNIT) - wait = 60*60*HZ; + switch (pc->c[0]) { + case GPCMD_BLANK: + case GPCMD_FORMAT_UNIT: + case GPCMD_RESERVE_RZONE_TRACK: + wait = WAIT_CMD; + break; + default: + wait = 0; + break; + } return wait; } @@ -658,8 +691,10 @@ called when the interrupt from the drive arrives. Otherwise, HANDLER will be called immediately after the drive is prepared for the transfer. */ -static ide_startstop_t cdrom_start_packet_command (ide_drive_t *drive, int xferlen, - ide_handler_t *handler) +static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive, + int xferlen, + ide_handler_t *handler, + int cmd) { ide_startstop_t startstop; struct cdrom_info *info = drive->driver_data; @@ -668,8 +703,15 @@ if (ide_wait_stat(&startstop, drive, 0, BUSY_STAT, WAIT_READY)) return startstop; - if (info->dma) - info->dma = !HWIF(drive)->dmaproc(ide_dma_read, drive); + if (info->dma) { + if (cmd == READ) { + info->dma = !HWIF(drive)->dmaproc(ide_dma_read, drive); + } else if (cmd == WRITE) { + info->dma = !HWIF(drive)->dmaproc(ide_dma_write, drive); + } else { + printk("ide-cd: DMA set, but not allowed\n"); + } + } /* Set up the controller registers. */ OUT_BYTE (info->dma, IDE_FEATURE_REG); @@ -701,7 +743,8 @@ or there's data ready. */ static ide_startstop_t cdrom_transfer_packet_command (ide_drive_t *drive, unsigned char *cmd_buf, int cmd_len, - ide_handler_t *handler) + ide_handler_t *handler, + unsigned timeout) { if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) { /* Here we should have been called after receiving an interrupt @@ -710,17 +753,17 @@ ide_startstop_t startstop; /* Check for errors. */ - if (cdrom_decode_status (&startstop, drive, DRQ_STAT, &stat_dum)) + if (cdrom_decode_status(&startstop, drive, DRQ_STAT, &stat_dum)) return startstop; } else { ide_startstop_t startstop; /* Otherwise, we must wait for DRQ to get set. */ - if (ide_wait_stat (&startstop, drive, DRQ_STAT, BUSY_STAT, WAIT_READY)) + if (ide_wait_stat(&startstop, drive, DRQ_STAT, BUSY_STAT, WAIT_READY)) return startstop; } /* Arm the interrupt handler. */ - ide_set_handler (drive, handler, WAIT_CMD, cdrom_timer_expiry); + ide_set_handler(drive, handler, timeout, cdrom_timer_expiry); /* Send the command to the device. */ atapi_output_bytes (drive, cmd_buf, cmd_len); @@ -1057,15 +1100,15 @@ (65534 / CD_FRAMESIZE) : 65535); /* Set up the command */ - memset (&pc.c, 0, sizeof (pc.c)); + memset(&pc.c, 0, sizeof(pc.c)); pc.c[0] = GPCMD_READ_10; pc.c[7] = (nframes >> 8); pc.c[8] = (nframes & 0xff); - put_unaligned(htonl (frame), (unsigned int *) &pc.c[2]); + put_unaligned(cpu_to_be32(frame), (unsigned int *) &pc.c[2]); /* Send the command to the drive and return. */ - return cdrom_transfer_packet_command (drive, pc.c, sizeof (pc.c), - &cdrom_read_intr); + return cdrom_transfer_packet_command(drive, pc.c, sizeof (pc.c), + &cdrom_read_intr, WAIT_CMD); } @@ -1105,10 +1148,11 @@ sector -= nskip; frame = sector / SECTORS_PER_FRAME; - memset (&pc.c, 0, sizeof (pc.c)); + memset(&pc.c, 0, sizeof(pc.c)); pc.c[0] = GPCMD_SEEK; put_unaligned(cpu_to_be32(frame), (unsigned int *) &pc.c[2]); - return cdrom_transfer_packet_command (drive, pc.c, sizeof (pc.c), &cdrom_seek_intr); + return cdrom_transfer_packet_command(drive, pc.c, sizeof (pc.c), + &cdrom_seek_intr, WAIT_CMD); } static ide_startstop_t cdrom_start_seek (ide_drive_t *drive, unsigned int block) @@ -1117,7 +1161,7 @@ info->dma = 0; info->start_seek = jiffies; - return cdrom_start_packet_command (drive, 0, cdrom_start_seek_continuation); + return cdrom_start_packet_command(drive, 0, cdrom_start_seek_continuation, 0); } /* Fix up a possibly partially-processed request so that we can @@ -1169,7 +1213,7 @@ info->dma = 0; /* Start sending the read request to the drive. */ - return cdrom_start_packet_command(drive, 32768, cdrom_start_read_continuation); + return cdrom_start_packet_command(drive, 32768, cdrom_start_read_continuation, READ); } /**************************************************************************** @@ -1177,19 +1221,17 @@ */ /* Forward declarations. */ -static int cdrom_lockdoor(ide_drive_t *drive, int lockflag); +static int cdrom_lockdoor(ide_drive_t *drive, int lockflag, + struct request_sense *sense); /* Interrupt routine for packet command completion. */ static ide_startstop_t cdrom_pc_intr (ide_drive_t *drive) { int ireason, len, stat, thislen; struct request *rq = HWGROUP(drive)->rq; - struct packet_command *pc = (struct packet_command *)rq->buffer; - struct cdrom_info *info = drive->driver_data; + struct packet_command *pc = (struct packet_command *) rq->buffer; ide_startstop_t startstop; - pc->sense_data = &info->sense_data; - /* Check for errors. */ if (cdrom_decode_status (&startstop, drive, 0, &stat)) return startstop; @@ -1286,8 +1328,8 @@ struct packet_command *pc = (struct packet_command *)rq->buffer; /* Send the command to the drive and return. */ - return cdrom_transfer_packet_command (drive, pc->c, - sizeof (pc->c), &cdrom_pc_intr); + return cdrom_transfer_packet_command(drive, pc->c, sizeof(pc->c), + &cdrom_pc_intr, WAIT_CMD); } @@ -1303,7 +1345,7 @@ len = pc->buflen; /* Start sending the command to the drive. */ - return cdrom_start_packet_command (drive, len, cdrom_do_pc_continuation); + return cdrom_start_packet_command(drive, len, cdrom_do_pc_continuation, 0); } @@ -1319,8 +1361,12 @@ static int cdrom_queue_packet_command(ide_drive_t *drive, struct packet_command *pc) { - int retries = 10; + struct request_sense sense; struct request req; + int retries = 10; + + if (pc->sense == NULL) + pc->sense = &sense; /* Start of retry loop. */ do { @@ -1336,7 +1382,7 @@ /* The request failed. Retry if it was due to a unit attention status (usually means media was changed). */ - struct request_sense *reqbuf = pc->sense_data; + struct request_sense *reqbuf = pc->sense; if (reqbuf->sense_key == UNIT_ATTENTION) cdrom_saw_media_change (drive); @@ -1357,31 +1403,176 @@ } while (pc->stat != 0 && retries >= 0); /* Return an error if the command failed. */ - if (pc->stat) - return -EIO; + return pc->stat ? -EIO : 0; +} - /* The command succeeded. If it was anything other than - a request sense, eject, or door lock command, - and we think that the door is presently unlocked, lock it - again. (The door was probably unlocked via an explicit - CDROMEJECT ioctl.) */ - if (CDROM_STATE_FLAGS (drive)->door_locked == 0 && - (pc->c[0] != GPCMD_TEST_UNIT_READY && - pc->c[0] != GPCMD_REQUEST_SENSE && - pc->c[0] != GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL && - pc->c[0] != GPCMD_START_STOP_UNIT && - pc->c[0] != GPCMD_MODE_SENSE_10 && - pc->c[0] != GPCMD_MODE_SELECT_10)) { - (void) cdrom_lockdoor (drive, 1); +/* + * Write handling + */ +static int cdrom_write_check_ireason(ide_drive_t *drive, int len, + int ireason) +{ + /* Two notes about IDE interrupt reason here - 0 means that + * the drive wants to receive data from us, 2 means that + * the drive is expecting data from us. + */ + ireason &= 3; + + if (ireason == 2) { + /* Whoops... The drive wants to send data. */ + printk("%s: cdrom_write_intr: wrong transfer direction!\n", + drive->name); + + /* Throw some data at the drive so it doesn't hang + and quit this request. */ + while (len > 0) { + int dum = 0; + atapi_output_bytes(drive, &dum, sizeof(dum)); + len -= sizeof(dum); + } + } else { + /* Drive wants a command packet, or invalid ireason... */ + printk("%s: cdrom_write_intr: bad interrupt reason %d\n", + drive->name, ireason); } - return 0; + + cdrom_end_request(0, drive); + return -1; +} + +static ide_startstop_t cdrom_write_intr(ide_drive_t *drive) +{ + int stat, ireason, len, sectors_to_transfer; + struct cdrom_info *info = drive->driver_data; + int i, dma_error = 0, dma = info->dma; + ide_startstop_t startstop; + + struct request *rq = HWGROUP(drive)->rq; + + /* Check for errors. */ + if (dma) { + info->dma = 0; + if ((dma_error = HWIF(drive)->dmaproc(ide_dma_end, drive))) { + printk("ide-cd: write dma error\n"); + HWIF(drive)->dmaproc(ide_dma_off, drive); + } + } + + if (cdrom_decode_status(&startstop, drive, 0, &stat)) { + printk("ide-cd: write_intr decode_status bad\n"); + return startstop; + } + + if (dma) { + if (dma_error) + return ide_error(drive, "dma error", stat); + + rq = HWGROUP(drive)->rq; + for (i = rq->nr_sectors; i > 0;) { + i -= rq->current_nr_sectors; + ide_end_request(1, HWGROUP(drive)); + } + printk("ide-cd: DMA write complete %lu (%lu)\n", rq->sector, rq->nr_sectors); + return ide_stopped; + } + + /* Read the interrupt reason and the transfer length. */ + ireason = IN_BYTE(IDE_NSECTOR_REG); + len = IN_BYTE(IDE_LCYL_REG) + 256 * IN_BYTE(IDE_HCYL_REG); + + /* If DRQ is clear, the command has completed. */ + if ((stat & DRQ_STAT) == 0) { + /* If we're not done writing, complain. + * Otherwise, complete the command normally. + */ + 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); + printk("ide-cd: DRQ write complete\n"); + return ide_stopped; + } + + /* Check that the drive is expecting to do the same thing we are. */ + if (ireason & 3) + 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 + */ + while (sectors_to_transfer > 0) { + unsigned long flags; + + /* 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); + spin_lock_irqsave(&io_request_lock, flags); + 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; + spin_unlock_irqrestore(&io_request_lock, flags); + } + + /* arm handler */ + ide_set_handler(drive, &cdrom_write_intr, 5 * WAIT_CMD, NULL); + return ide_started; +} + +static ide_startstop_t cdrom_start_write_cont(ide_drive_t *drive) +{ + struct packet_command pc; + struct request *rq = HWGROUP(drive)->rq; + int nframes, frame; + + nframes = rq->nr_sectors >> 2; + frame = rq->sector >> 2; + + memset(&pc.c, 0, sizeof(pc.c)); + /* + * we might as well use WRITE_12, but none of the device I have + * support the streaming feature anyway, so who cares. + */ + pc.c[0] = GPCMD_WRITE_10; +#if 0 + pc.c[1] = 1 << 3; +#endif + pc.c[7] = (nframes >> 8) & 0xff; + pc.c[8] = nframes & 0xff; + put_unaligned(cpu_to_be32(frame), (unsigned int *)&pc.c[2]); + + return cdrom_transfer_packet_command(drive, pc.c, sizeof(pc.c), + cdrom_write_intr, 2 * WAIT_CMD); +} + +static ide_startstop_t cdrom_start_write(ide_drive_t *drive) +{ + struct cdrom_info *info = drive->driver_data; + + info->nsectors_buffered = 0; + + /* use dma, if possible. we don't need to check more, since we + * know that the transfer is always (at least!) 2KB aligned */ + info->dma = drive->using_dma ? 1 : 0; + + /* Start sending the read request to the drive. */ + return cdrom_start_packet_command(drive, 32768, cdrom_start_write_cont, WRITE); } /**************************************************************************** * cdrom driver request routine. */ static ide_startstop_t -ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, unsigned long block) +ide_do_rw_cdrom(ide_drive_t *drive, struct request *rq, unsigned long block) { ide_startstop_t action; struct cdrom_info *info = drive->driver_data; @@ -1418,7 +1609,10 @@ cdrom_end_request(1, drive); return ide_do_reset(drive); } - + case WRITE_PACKET: { + printk("ide-cd: got WRITE_PACKET %lu-%lu\n", rq->sector, rq->nr_sectors); + return cdrom_start_write(drive); + } default: { printk("ide-cd: bad cmd %d\n", rq -> cmd); cdrom_end_request(0, drive); @@ -1482,13 +1676,14 @@ return (((m * CD_SECS) + s) * CD_FRAMES + f) - CD_MSF_OFFSET; } -static int cdrom_check_status (ide_drive_t *drive) +static int cdrom_check_status(ide_drive_t *drive, struct request_sense *sense) { struct packet_command pc; struct cdrom_info *info = drive->driver_data; struct cdrom_device_info *cdi = &info->devinfo; memset(&pc, 0, sizeof(pc)); + pc.sense = sense; pc.c[0] = GPCMD_TEST_UNIT_READY; @@ -1505,24 +1700,26 @@ /* Lock the door if LOCKFLAG is nonzero; unlock it otherwise. */ static int -cdrom_lockdoor(ide_drive_t *drive, int lockflag) +cdrom_lockdoor(ide_drive_t *drive, int lockflag, struct request_sense *sense) { - struct request_sense *sense; + struct request_sense my_sense; struct packet_command pc; int stat; + if (sense == NULL) + sense = &my_sense; + /* If the drive cannot lock the door, just pretend. */ if (CDROM_CONFIG_FLAGS (drive)->no_doorlock) stat = 0; else { memset(&pc, 0, sizeof(pc)); + pc.sense = sense; pc.c[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL; pc.c[4] = (lockflag != 0); stat = cdrom_queue_packet_command (drive, &pc); } - sense = pc.sense_data; - /* If we got an illegal field error, the drive probably cannot lock the door. */ if (stat != 0 && @@ -1547,7 +1744,8 @@ /* Eject the disk if EJECTFLAG is 0. If EJECTFLAG is 1, try to reload the disk. */ -static int cdrom_eject(ide_drive_t *drive, int ejectflag) +static int cdrom_eject(ide_drive_t *drive, int ejectflag, + struct request_sense *sense) { struct packet_command pc; @@ -1559,13 +1757,15 @@ return 0; memset(&pc, 0, sizeof (pc)); + pc.sense = sense; pc.c[0] = GPCMD_START_STOP_UNIT; pc.c[4] = 0x02 + (ejectflag != 0); return cdrom_queue_packet_command (drive, &pc); } -static int cdrom_read_capacity(ide_drive_t *drive, unsigned *capacity) +static int cdrom_read_capacity(ide_drive_t *drive, unsigned *capacity, + struct request_sense *sense) { struct { __u32 lba; @@ -1576,6 +1776,7 @@ struct packet_command pc; memset(&pc, 0, sizeof (pc)); + pc.sense = sense; pc.c[0] = GPCMD_READ_CDVD_CAPACITY; pc.buffer = (char *)&capbuf; @@ -1589,11 +1790,13 @@ } static int cdrom_read_tocentry(ide_drive_t *drive, int trackno, int msf_flag, - int format, char *buf, int buflen) + int format, char *buf, int buflen, + struct request_sense *sense) { struct packet_command pc; memset(&pc, 0, sizeof(pc)); + pc.sense = sense; pc.buffer = buf; pc.buflen = buflen; @@ -1611,7 +1814,7 @@ /* Try to read the entire TOC for the disk into our internal buffer. */ -static int cdrom_read_toc (ide_drive_t *drive) +static int cdrom_read_toc (ide_drive_t *drive, struct request_sense *sense) { int stat, ntracks, i; struct cdrom_info *info = drive->driver_data; @@ -1636,13 +1839,13 @@ /* Check to see if the existing data is still valid. If it is, just return. */ if (CDROM_STATE_FLAGS (drive)->toc_valid) - (void) cdrom_check_status(drive); + (void) cdrom_check_status(drive, sense); if (CDROM_STATE_FLAGS (drive)->toc_valid) return 0; /* First read just the header, so we know how long the TOC is. */ - stat = cdrom_read_tocentry (drive, 0, 1, 0, (char *)&toc->hdr, - sizeof (struct atapi_toc_header)); + stat = cdrom_read_tocentry(drive, 0, 1, 0, (char *)&toc->hdr, + sizeof(struct atapi_toc_header), sense); if (stat) return stat; #if ! STANDARD_ATAPI @@ -1660,7 +1863,7 @@ stat = cdrom_read_tocentry (drive, toc->hdr.first_track, 1, 0, (char *)&toc->hdr, sizeof (struct atapi_toc_header) + (ntracks + 1) * - sizeof (struct atapi_toc_entry)); + sizeof (struct atapi_toc_entry), sense); if (stat && toc->hdr.first_track > 1) { /* Cds with CDI tracks only don't have any TOC entries, @@ -1675,9 +1878,9 @@ ntracks = 0; stat = cdrom_read_tocentry (drive, CDROM_LEADOUT, 1, 0, (char *)&toc->hdr, - sizeof (struct atapi_toc_header) + + sizeof(struct atapi_toc_header) + (ntracks+1) * - sizeof (struct atapi_toc_entry)); + sizeof(struct atapi_toc_entry), sense); if (stat) { return stat; } @@ -1721,8 +1924,8 @@ /* Read the multisession information. */ if (toc->hdr.first_track != CDROM_LEADOUT) { /* Read the multisession information. */ - stat = cdrom_read_tocentry (drive, 0, 1, 1, - (char *)&ms_tmp, sizeof (ms_tmp)); + stat = cdrom_read_tocentry(drive, 0, 1, 1, (char *)&ms_tmp, + sizeof (ms_tmp), sense); if (stat) return stat; } else { ms_tmp.ent.addr.msf.minute = 0; @@ -1748,7 +1951,7 @@ (long *)&toc->capacity); if (stat) #endif - stat = cdrom_read_capacity (drive, &toc->capacity); + stat = cdrom_read_capacity (drive, &toc->capacity, sense); if (stat) toc->capacity = 0x1fffff; /* for general /dev/cdrom like mounting, one big disc */ @@ -1764,29 +1967,32 @@ return 0; /* setup each minor to respond to a session */ +#if 0 minor++; i = toc->hdr.first_track; while ((i <= ntracks) && ((minor & CD_PART_MASK) < CD_PART_MAX)) { drive->part[minor & PARTN_MASK].start_sect = 0; drive->part[minor & PARTN_MASK].nr_sects = (toc->ent[i].addr.lba * - SECTORS_PER_FRAME) << (BLOCK_SIZE_BITS - 9); + SECTORS_PER_FRAME) << 2; HWIF(drive)->gd->sizes[minor] = (toc->ent[i].addr.lba * SECTORS_PER_FRAME) >> (BLOCK_SIZE_BITS - 9); i++; minor++; } +#endif return 0; } static int cdrom_read_subchannel(ide_drive_t *drive, int format, char *buf, - int buflen) + int buflen, struct request_sense *sense) { struct packet_command pc; memset(&pc, 0, sizeof(pc)); + pc.sense = sense; pc.buffer = buf; pc.buflen = buflen; @@ -1801,10 +2007,12 @@ /* ATAPI cdrom drives are free to select the speed you request or any slower rate :-( Requesting too fast a speed will _not_ produce an error. */ -static int cdrom_select_speed (ide_drive_t *drive, int speed) +static int cdrom_select_speed (ide_drive_t *drive, int speed, + struct request_sense *sense) { struct packet_command pc; memset(&pc, 0, sizeof(pc)); + pc.sense = sense; if (speed == 0) speed = 0xffff; /* set to max */ @@ -1829,7 +2037,8 @@ static int cdrom_get_toc_entry(ide_drive_t *drive, int track, - struct atapi_toc_entry **ent) + struct atapi_toc_entry **ent, + struct request_sense *sense) { struct cdrom_info *info = drive->driver_data; struct atapi_toc *toc = info->toc; @@ -1869,9 +2078,7 @@ pc.buflen = cgc->buflen; cgc->stat = cdrom_queue_packet_command(drive, &pc); - /* There was an error, assign sense. */ - if (cgc->stat) - cgc->sense = pc.sense_data; + cgc->sense = pc.sense; return cgc->stat; } @@ -1937,7 +2144,7 @@ struct atapi_toc *toc; /* Make sure our saved TOC is valid. */ - stat = cdrom_read_toc(drive); + stat = cdrom_read_toc(drive, NULL); if (stat) return stat; toc = info->toc; @@ -1952,7 +2159,8 @@ struct cdrom_tocentry *tocentry = (struct cdrom_tocentry*) arg; struct atapi_toc_entry *toce; - stat = cdrom_get_toc_entry (drive, tocentry->cdte_track, &toce); + stat = cdrom_get_toc_entry(drive, tocentry->cdte_track, &toce, + NULL); if (stat) return stat; tocentry->cdte_ctrl = toce->control; @@ -1977,11 +2185,21 @@ int ide_cdrom_reset (struct cdrom_device_info *cdi) { ide_drive_t *drive = (ide_drive_t*) cdi->handle; + struct request_sense sense; struct request req; + int ret; ide_init_drive_cmd (&req); req.cmd = RESET_DRIVE_COMMAND; - return ide_do_drive_cmd (drive, &req, ide_wait); + ret = ide_do_drive_cmd (drive, &req, ide_wait); + + /* A reset will unlock the door. If it was previously locked, + * lock it again. + */ + if (CDROM_STATE_FLAGS(drive)->door_locked) + (void) cdrom_lockdoor(drive, 1, &sense); + + return ret; } @@ -1989,20 +2207,21 @@ int ide_cdrom_tray_move (struct cdrom_device_info *cdi, int position) { ide_drive_t *drive = (ide_drive_t*) cdi->handle; + struct request_sense sense; if (position) { - int stat = cdrom_lockdoor (drive, 0); + int stat = cdrom_lockdoor(drive, 0, &sense); if (stat) return stat; } - return cdrom_eject(drive, !position); + return cdrom_eject(drive, !position, &sense); } static int ide_cdrom_lock_door (struct cdrom_device_info *cdi, int lock) { ide_drive_t *drive = (ide_drive_t*) cdi->handle; - return cdrom_lockdoor (drive, lock); + return cdrom_lockdoor(drive, lock, NULL); } #undef __ACER50__ @@ -2060,20 +2279,19 @@ { #ifndef __ACER50__ int stat, attempts = 3; - ide_drive_t *drive = (ide_drive_t*) cdi->handle; - struct cdrom_generic_command cgc; struct { char pad[8]; struct atapi_capabilities_page cap; } buf; #else int stat; - ide_drive_t *drive = (ide_drive_t*) cdi->handle; - struct cdrom_generic_command cgc; struct get_capabilities_buf buf; #endif /* __ACER50__ */ + ide_drive_t *drive = (ide_drive_t*) cdi->handle; + struct cdrom_generic_command cgc; + struct request_sense sense; - if ((stat = cdrom_select_speed (drive, speed)) < 0) + if ((stat = cdrom_select_speed (drive, speed, &sense)) < 0) return stat; init_cdrom_command(&cgc, &buf, sizeof(buf)); @@ -2111,19 +2329,18 @@ int ide_cdrom_drive_status (struct cdrom_device_info *cdi, int slot_nr) { ide_drive_t *drive = (ide_drive_t*) cdi->handle; - struct cdrom_info *info = drive->driver_data; if (slot_nr == CDSL_CURRENT) { - struct request_sense *sense = &info->sense_data; - int stat = cdrom_check_status(drive); - if (stat == 0 || sense->sense_key == UNIT_ATTENTION) + struct 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) + if (sense.sense_key == NOT_READY && sense.asc == 0x04 && + sense.ascq == 0x04) return CDS_DISC_OK; - if (sense->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. */ @@ -2160,7 +2377,7 @@ ide_drive_t *drive = (ide_drive_t*) cdi->handle; /* get MCN */ - if ((stat = cdrom_read_subchannel(drive, 2, mcnbuf, sizeof (mcnbuf)))) + if ((stat = cdrom_read_subchannel(drive, 2, mcnbuf, sizeof(mcnbuf), NULL))) return stat; memcpy (mcn_info->medium_catalog_number, mcnbuf+9, @@ -2184,7 +2401,7 @@ ide_drive_t *drive = (ide_drive_t*) cdi->handle; if (slot_nr == CDSL_CURRENT) { - (void) cdrom_check_status(drive); + (void) cdrom_check_status(drive, NULL); CDROM_STATE_FLAGS (drive)->media_changed = 0; return CDROM_STATE_FLAGS (drive)->media_changed; } else { @@ -2245,7 +2462,11 @@ struct cdrom_device_info *devinfo = &info->devinfo; int minor = (drive->select.b.unit)<dev = MKDEV (HWIF(drive)->major, minor | CD_PART_MASK); +#else + devinfo->dev = MKDEV (HWIF(drive)->major, minor); +#endif devinfo->ops = &ide_cdrom_dops; devinfo->mask = 0; *(int *)&devinfo->speed = CDROM_STATE_FLAGS (drive)->current_speed; @@ -2270,8 +2491,8 @@ devinfo->mask |= CDC_PLAY_AUDIO; if (!CDROM_CONFIG_FLAGS (drive)->close_tray) devinfo->mask |= CDC_CLOSE_TRAY; - - return register_cdrom (devinfo); + + return register_cdrom(devinfo); } @@ -2421,7 +2642,7 @@ int major = HWIF(drive)->major; int minor = drive->select.b.unit << PARTN_BITS; - ide_add_setting(drive, "breada_readahead", SETTING_RW, BLKRAGET, BLKRASET, TYPE_INT, 0, 255, 1, 2, &read_ahead[major], NULL); + ide_add_setting(drive, "breada_readahead", SETTING_RW, BLKRAGET, BLKRASET, TYPE_INT, 0, 255, 1, 1024, &read_ahead[major], NULL); ide_add_setting(drive, "file_readahead", SETTING_RW, BLKFRAGET, BLKFRASET, TYPE_INTA, 0, INT_MAX, 1, 1024, &max_readahead[major][minor], NULL); ide_add_setting(drive, "max_kb_per_request", SETTING_RW, BLKSECTGET, BLKSECTSET, TYPE_INTA, 1, 255, 1, 2, &max_sectors[major][minor], NULL); ide_add_setting(drive, "dsc_overlap", SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->dsc_overlap, NULL); @@ -2435,7 +2656,7 @@ int minor = drive->select.b.unit << PARTN_BITS; int nslots; - set_device_ro(MKDEV(HWIF(drive)->major, minor), 1); + set_device_ro(MKDEV(HWIF(drive)->major, minor), 0); set_blocksize(MKDEV(HWIF(drive)->major, minor), CD_FRAMESIZE); drive->special.all = 0; @@ -2581,12 +2802,11 @@ MOD_INC_USE_COUNT; if (info->buffer == NULL) info->buffer = (char *) kmalloc(SECTOR_BUFFER_SIZE, GFP_KERNEL); - rc = cdrom_fops.open (ip, fp); - if (rc) { + if ((rc = cdrom_fops.open(ip, fp))) { drive->usage--; MOD_DEC_USE_COUNT; } - return rc; + return 0; } static @@ -2611,7 +2831,7 @@ struct cdrom_info *info = drive->driver_data; struct cdrom_device_info *devinfo = &info->devinfo; - if (ide_unregister_subdriver (drive)) + if (ide_unregister_subdriver(drive)) return 1; if (info->buffer != NULL) kfree(info->buffer); @@ -2619,7 +2839,7 @@ kfree(info->toc); if (info->changer_info != NULL) kfree(info->changer_info); - if (devinfo->handle == drive && unregister_cdrom (devinfo)) + if (devinfo->handle == drive && unregister_cdrom(devinfo)) printk ("%s: ide_cdrom_cleanup failed to unregister device from the cdrom driver.\n", drive->name); kfree(info); drive->driver_data = NULL; diff -urN --exclude-from exclude-from linux-2.3.43-clean/drivers/block/ide-cd.h linux-2.3.43/drivers/block/ide-cd.h --- linux-2.3.43-clean/drivers/block/ide-cd.h Sat Jan 8 00:30:16 2000 +++ linux-2.3.43/drivers/block/ide-cd.h Thu Feb 10 21:12:32 2000 @@ -103,7 +103,7 @@ char *buffer; int buflen; int stat; - struct request_sense *sense_data; + struct request_sense *sense; unsigned char c[12]; }; @@ -626,7 +626,9 @@ "Logical unit not ready - in progress [sic] of becoming ready" }, { 0x020402, "Logical unit not ready - initializing command required" }, { 0x020403, "Logical unit not ready - manual intervention required" }, - { 0x020404, "In process of becoming ready - writing" }, + { 0x020404, "Logical unit not ready - format in progress" }, + { 0x020407, "Logical unit not ready - operation in progress" }, + { 0x020408, "Logical unit not ready - long write in progress" }, { 0x020600, "No reference position found (media may be upside down)" }, { 0x023000, "Incompatible medium installed" }, { 0x023a00, "Medium not present" }, @@ -676,7 +678,6 @@ { 0x04b600, "Media load mechanism failed" }, { 0x051a00, "Parameter list length error" }, { 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" }, diff -urN --exclude-from exclude-from linux-2.3.43-clean/drivers/block/ide.c linux-2.3.43/drivers/block/ide.c --- linux-2.3.43-clean/drivers/block/ide.c Tue Feb 8 22:59:16 2000 +++ linux-2.3.43/drivers/block/ide.c Tue Feb 8 22:16:24 2000 @@ -1095,11 +1095,13 @@ #endif block = rq->sector; blockend = block + rq->nr_sectors; +#if 0 if ((blockend < block) || (blockend > drive->part[minor&PARTN_MASK].nr_sects)) { printk("%s%c: bad access: block=%ld, count=%ld\n", drive->name, (minor&PARTN_MASK)?'0'+(minor&PARTN_MASK):' ', block, rq->nr_sectors); goto kill_rq; } +#endif block += drive->part[minor&PARTN_MASK].start_sect + drive->sect0; /* Yecch - this will shift the entire interval, @@ -1417,9 +1419,9 @@ } } else { ide_drive_t *drive = hwgroup->drive; - hwgroup->handler = NULL; if (!drive) { printk("ide_timer_expiry: hwgroup->drive was NULL\n"); + hwgroup->handler = NULL; } else { ide_hwif_t *hwif; ide_startstop_t startstop; @@ -1431,12 +1433,13 @@ /* continue */ if ((wait = expiry(drive)) != 0) { /* reset timer */ - hwgroup->timer.expires = jiffies + wait; + hwgroup->timer.expires = jiffies + wait; add_timer(&hwgroup->timer); spin_unlock_irqrestore(&io_request_lock, flags); return; } } + hwgroup->handler = NULL; /* * We need to simulate a real interrupt when invoking * the handler() function, which means we need to globally diff -urN --exclude-from exclude-from linux-2.3.43-clean/drivers/block/ll_rw_blk.c linux-2.3.43/drivers/block/ll_rw_blk.c --- linux-2.3.43-clean/drivers/block/ll_rw_blk.c Thu Feb 10 06:42:34 2000 +++ linux-2.3.43/drivers/block/ll_rw_blk.c Fri Feb 11 07:05:17 2000 @@ -3,6 +3,7 @@ * * Copyright (C) 1991, 1992 Linus Torvalds * Copyright (C) 1994, Karl Keyte: Added support for disk statistics + * Copyright (C) 2000 Jens Axboe : new merge logic */ /* @@ -167,21 +168,41 @@ q->make_request_fn = mfn; } -static int ll_merge_fn(request_queue_t *q, struct request *req, - struct buffer_head *bh) +static int inline ll_merge_bh_fn(struct request *req, struct buffer_head *bh) { - if (req->bhtail->b_data + req->bhtail->b_size != bh->b_data) { + if (req->sector + req->nr_sectors == bh->b_rsector) { + req->bhtail->b_reqnext = bh; + req->bhtail = bh; + req->nr_sectors += bh->b_size >> 9; + return 1; + } + if ((req->sector - (bh->b_size >> 9)) == bh->b_rsector) { + bh->b_reqnext = req->bh; + req->bh = bh; + req->buffer = bh->b_data; + req->current_nr_sectors = bh->b_size >> 9; + req->sector = bh->b_rsector; + req->nr_sectors += bh->b_size >> 9; + return 1; + } + return 0; +} + +static int inline ll_merge_fn(request_queue_t *q, struct request *req, + struct buffer_head *bh) +{ + if (req->bhtail->b_data + req->bhtail->b_size != bh->b_data) { if (req->nr_segments < MAX_SEGMENTS) { - req->nr_segments++; + req->nr_segments++; return 1; } return 0; - } + } return 1; } -static int ll_merge_requests_fn(request_queue_t *q, struct request *req, - struct request *next) +static int inline ll_merge_requests_fn(request_queue_t *q, struct request *req, + struct request *next) { int total_segments = req->nr_segments + next->nr_segments; @@ -197,23 +218,24 @@ void blk_init_queue(request_queue_t * q, request_fn_proc * rfn) { - q->request_fn = rfn; + q->request_fn = rfn; q->current_request = NULL; - q->merge_fn = ll_merge_fn; + q->merge_fn = ll_merge_fn; q->merge_requests_fn = ll_merge_requests_fn; + q->merge_bh_fn = ll_merge_bh_fn; + q->plug_tq.sync = 0; + q->plug_tq.routine = generic_unplug_device; + q->plug_tq.data = q; + q->plugged = 0; q->make_request_fn = NULL; - q->plug_tq.sync = 0; - q->plug_tq.routine = &generic_unplug_device; - q->plug_tq.data = q; - q->plugged = 0; /* * These booleans describe the queue properties. We set the * default (and most common) values here. Other drivers can * use the appropriate functions to alter the queue properties. * as appropriate. */ - q->plug_device_fn = NULL; - q->head_active = 1; + q->plug_device_fn = NULL; + q->head_active = 1; } /* @@ -404,9 +426,9 @@ struct request * tmp; drive_stat_acct(req, req->nr_sectors, 1); - req->next = NULL; if (!(tmp = q->current_request)) { + req->next = NULL; q->current_request = req; return; } @@ -446,9 +468,8 @@ /* * Has to be called with the request spinlock aquired */ -static inline void attempt_merge (request_queue_t * q, - struct request *req, - int max_sectors) +static inline void attempt_merge(request_queue_t *q, struct request *req, + int max_sectors) { struct request *next = req->next; @@ -472,25 +493,24 @@ req->nr_sectors += next->nr_sectors; next->rq_status = RQ_INACTIVE; req->next = next->next; - wake_up (&wait_for_request); + wake_up(&wait_for_request); } static inline void __make_request(request_queue_t * q, int rw, struct buffer_head * bh) { int major = MAJOR(bh->b_rdev); - unsigned int sector, count; + unsigned int count; struct request * req; int rw_ahead, max_req, max_sectors; unsigned long flags; count = bh->b_size >> 9; - sector = bh->b_rsector; if (blk_size[major]) { unsigned long maxsector = (blk_size[major][MINOR(bh->b_rdev)] << 1) + 1; - if (maxsector < count || maxsector - count < sector) { + if (maxsector < count || maxsector - count < bh->b_rsector) { bh->b_state &= (1 << BH_Lock) | (1 << BH_Mapped); if (!blk_size[major][MINOR(bh->b_rdev)]) goto end_io; @@ -499,9 +519,9 @@ when mounting a device. */ printk(KERN_INFO "attempt to access beyond end of device\n"); - printk(KERN_INFO "%s: rw=%d, want=%d, limit=%d\n", + printk(KERN_INFO "%s: rw=%d, want=%ld, limit=%d\n", kdevname(bh->b_rdev), rw, - (sector + count)>>1, + (bh->b_rsector + count)>>1, blk_size[major][MINOR(bh->b_rdev)]); goto end_io; } @@ -608,57 +628,15 @@ continue; if (req->rq_dev != bh->b_rdev) continue; - /* Can we add it to the end of this request? */ - if (req->sector + req->nr_sectors == sector) { - /* - * The merge_fn is a more advanced way - * of accomplishing the same task. Instead - * of applying a fixed limit of some sort - * we instead define a function which can - * determine whether or not it is safe to - * merge the request or not. - * - * See if this queue has rules that - * may suggest that we shouldn't merge - * this - */ - if(!(q->merge_fn)(q, req, bh)) - continue; - req->bhtail->b_reqnext = bh; - req->bhtail = bh; - req->nr_sectors += count; - drive_stat_acct(req, count, 0); - /* Can we now merge this req with the next? */ - attempt_merge(q, req, max_sectors); - /* or to the beginning? */ - } else if (req->sector - count == sector) { - /* - * The merge_fn is a more advanced way - * of accomplishing the same task. Instead - * of applying a fixed limit of some sort - * we instead define a function which can - * determine whether or not it is safe to - * merge the request or not. - * - * See if this queue has rules that - * may suggest that we shouldn't merge - * this - */ - if(!(q->merge_fn)(q, req, bh)) - continue; - bh->b_reqnext = req->bh; - req->bh = bh; - req->buffer = bh->b_data; - req->current_nr_sectors = count; - req->sector = sector; - req->nr_sectors += count; - drive_stat_acct(req, count, 0); - } else + if (!(q->merge_fn(q, req, bh))) + continue; + if (!(q->merge_bh_fn(req, bh))) continue; + drive_stat_acct(req, count, 0); + attempt_merge(q, req, max_sectors); spin_unlock_irqrestore(&io_request_lock,flags); return; - } while ((req = req->next) != NULL); /* find an unused request. */ @@ -698,7 +676,7 @@ /* fill up the request-info, and add it to the queue */ req->cmd = rw; req->errors = 0; - req->sector = sector; + req->sector = bh->b_rsector; req->nr_sectors = count; req->current_nr_sectors = count; req->nr_segments = 1; /* Always 1 for a new request. */ @@ -707,7 +685,6 @@ req->sem = NULL; req->bh = bh; req->bhtail = bh; - req->next = NULL; __add_request(q, req); spin_unlock_irqrestore(&io_request_lock, flags); return; @@ -854,6 +831,7 @@ bh->b_end_io(bh, uptodate); if ((bh = req->bh) != NULL) { req->current_nr_sectors = bh->b_size >> 9; + req->sector = bh->b_rsector; if (req->nr_sectors < req->current_nr_sectors) { req->nr_sectors = req->current_nr_sectors; printk("end_request: buffer-list destroyed\n"); @@ -884,10 +862,8 @@ } req = all_requests + NR_REQUEST; - while (--req >= all_requests) { + while (--req >= all_requests) req->rq_status = RQ_INACTIVE; - req->next = NULL; - } memset(ro_bits,0,sizeof(ro_bits)); memset(max_readahead, 0, sizeof(max_readahead)); memset(max_sectors, 0, sizeof(max_sectors)); @@ -998,5 +974,6 @@ EXPORT_SYMBOL(blk_init_queue); EXPORT_SYMBOL(blk_cleanup_queue); EXPORT_SYMBOL(blk_queue_headactive); +EXPORT_SYMBOL(blk_get_queue); EXPORT_SYMBOL(generic_make_request); -EXPORT_SYMBOL(blk_queue_pluggable); +EXPORT_SYMBOL(generic_unplug_device); diff -urN --exclude-from exclude-from linux-2.3.43-clean/drivers/block/packet.c linux-2.3.43/drivers/block/packet.c --- linux-2.3.43-clean/drivers/block/packet.c Thu Jan 1 01:00:00 1970 +++ linux-2.3.43/drivers/block/packet.c Fri Feb 11 07:41:38 2000 @@ -0,0 +1,1138 @@ +/* + * Copyright (C) 2000 Jens Axboe + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + * Packet writing layer for ATAPI and SCSI CD-R, CD-RW, DVD-R, and + * DVD-RW devices. + * + * + * TODO: (circa order of when I will fix it) + * - do proper LRA for effiency, if possible (for CD-RW) + * - fix SCSI layer so we can use SCSI CD writers too + * - Only able to write on CD-RW media right now. + * - Generic interface for UDF to submit large packets for variable length + * packet writing. + * - (in correlation with above) interface for UDF <-> packet to negotiate + * a new location when a write fails. + * - handle OPC, especially for -RW media + * - /proc/driver/packet with info + * - Lots of stuff ;) + * + *************************************************************************/ + +#define VERSION_CODE "v0.0.1f Jens Axboe " + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +extern void end_buffer_io_sync(struct buffer_head *bh, int uptodate); +extern void end_buffer_io_async(struct buffer_head *bh, int uptodate); + +/* + * 1 for normal debug messages, 2 is very verbose. 0 to turn it off. + */ +#define PACKET_DEBUG 2 + +#define PACKET_MAJOR 42 +#define MAX_WRITERS 4 + +/* + * 64 * 1024 sectors + */ +#define PACKET_MAX_SIZE 64 + +#define NEXT_BH(bh, nbh) (((bh)->b_rsector + ((bh)->b_size >> 9)) == (nbh)->b_rsector) + +#define BH_IN_ORDER(b1, b2) ((b1)->b_rsector < (b2)->b_rsector) + +#define ZONE(sector, span) ((sector) - ((sector) % (span))) + +#define ASSERT(expr) \ + if (!(expr)) { \ + printk("assert failed %s,%s at %d\n", \ + #expr, __FUNCTION__, __LINE__); \ + } + +#if PACKET_DEBUG +#define DPRINTK(fmt, args...) printk(KERN_NOTICE fmt, ##args) +#else +#define DPRINTK(fmt, args...) +#endif + +#if PACKET_DEBUG > 1 +#define VPRINTK(fmt, args...) printk(KERN_NOTICE fmt, ##args) +#else +#define VPRINTK(fmt, args...) +#endif + +static int *packet_sizes; +static int *packet_blksize; +static struct packet_device *packet_devs; + +/* + * write mode select package based on pd->settings + */ +static int pkt_write_settings(struct packet_device *pd) +{ + write_param_page wp; + struct cdrom_generic_command cgc; + int stat; + + memset(&wp, 0, sizeof(write_param_page)); + init_cdrom_command(&cgc, &wp, sizeof(write_param_page)); + + stat = cdrom_mode_sense(pd->cdi, &cgc, GPMODE_WRITE_PARMS_PAGE, 0); + if (stat) + return stat; + + wp.fp = pd->settings.fp; + wp.track_mode = pd->settings.track_mode; + wp.write_type = pd->settings.write_type; + wp.data_block_type = pd->settings.block_mode; + + wp.session_format = 0x20; + wp.multi_session = 0; + + /* FIXME: only for FP */ + wp.subhdr2 = 0x20; + wp.packet_size = cpu_to_be32(pd->settings.size >> 2); + + /* some writers are so picky about length ;) */ + cgc.cmd[8] = be16_to_cpu(wp.header.desc_length) + sizeof(wp.header.desc_length); + cgc.buflen = cgc.cmd[8]; + if ((stat = cdrom_mode_select(pd->cdi, &cgc))) + return stat; + + /* settings now saved! print info */ + printk("packet: %s writable with %u sized %s packets\n", pd->name, + pd->settings.size >> 2, + pd->settings.fp ? "fixed" : "variable"); + + return 0; +} + +/* + * 0 -- we can write to this track, 1 -- we can't + */ +static int pkt_good_track(track_information *ti) +{ + /* only good for CD-RW at the moment, not DVD-RW */ + + /* FIXME: only for FP */ + if (ti->fp == 0) + return 0; + + /* "good" settings as per Mt Fuji. */ + if (ti->rt == 0 && ti->blank == 0 && ti->packet == 1) + return 0; + + if (ti->rt == 0 && ti->blank == 1 && ti->packet == 1) + return 0; + + if (ti->rt == 1 && ti->blank == 0 && ti->packet == 1) + return 0; + + printk("packet: bad state %d-%d-%d\n", ti->rt, ti->blank, ti->packet); + return 1; +} + +/* + * 0 -- we can write to this disc, 1 -- we can't + */ +static int pkt_good_disc(struct packet_device *pd, disc_information *di) +{ + /* for disc type 0xff we should probably reserve a new track. + * but i'm not sure, should we leave this to user apps? probably. + */ + if (di->disc_type == 0xff) { + printk("packet: Unknown disc. No track?\n"); + return 1; + } + + if (di->disc_type != 0x20 && di->disc_type != 0) { + printk("packet: Wrong disc type (%x)\n", di->disc_type); + return 1; + } + + if (di->erasable == 0) { + printk("packet: Disc not erasable\n"); + return 1; + } + + if (pd->track_status == PACKET_SESSION_RESERVED) { + printk("packet: Can't write to last track (reserved)\n"); + return 1; + } + + return 0; +} + +static int pkt_probe_settings(struct packet_device *pd) +{ + disc_information di; + track_information ti; + int stat, track; + + memset(&di, 0, sizeof(disc_information)); + memset(&ti, 0, sizeof(track_information)); + + if ((stat = cdrom_get_disc_info(pd->dev, &di))) { + printk("failed get_disc\n"); + return stat; + } + + pd->disc_status = di.disc_status; + pd->track_status = di.border_status; + + if (pkt_good_disc(pd, &di)) + return -ENXIO; + + printk("packet: inserted media is CD-R%s\n", di.erasable ? "W" : ""); + + track = (di.last_track_msb << 8) | di.last_track_lsb; + if ((stat = cdrom_get_track_info(pd->dev, track, 1, &ti))) { + printk("failed get_track\n"); + return stat; + } + + if (pkt_good_track(&ti)) { + printk("packet: can't write to this track\n"); + return -ENXIO; + } + + pd->settings.size = be32_to_cpu(ti.fixed_packet_size) << 2; + pd->settings.fp = ti.fp; + + if (ti.nwa_v) { + pd->nwa = be32_to_cpu(ti.next_writable); + pd->flags |= PACKET_NWA_VALID; + } + + /* + * in theory we could use lra on -RW media as well and just zero + * blocks that haven't been written yet, but in practice that + * is just a no-go. we'll use that for -R, naturally. + */ + if (ti.lra_v) { + pd->lra = be32_to_cpu(ti.last_rec_address); + pd->flags |= PACKET_LRA_VALID; + } else { + pd->lra = 0xffffffff; + pd->flags |= PACKET_LRA_VALID; + } + + /* fine for now */ + pd->settings.link_loss = 0x10; + pd->settings.write_type = 0; /* packet */ + pd->settings.track_mode = ti.track_mode; + if (ti.data_mode == 1) + pd->settings.block_mode = 8; /* Mode 1 */ + else if (ti.data_mode == 2) + pd->settings.block_mode = 10; + else { + printk("packet: unknown data mode (%x)\n", ti.data_mode); + return 1; + } + return 0; +} + +/* + * flush the drive cache to media + */ +static int pkt_flush_cache(struct packet_device *pd) +{ + struct cdrom_generic_command cgc; + struct cdrom_device_info *cdi = pd->cdi; + + init_cdrom_command(&cgc, NULL, 0); + cgc.cmd[0] = GPCMD_FLUSH_CACHE; + + /* + * the IMMED bit -- we default to not setting it, although that + * would allow a much faster close + */ +#if 0 + cgc.cmd[1] = 1 << 1; +#endif + return cdi->ops->generic_packet(cdi, &cgc); +} + +/* + * speed is given as the normal factor, e.g. 4 for 4x + */ +int pkt_set_write_speed(struct packet_device *pd, int speed) +{ + struct cdrom_generic_command cgc; + struct cdrom_device_info *cdi = pd->cdi; + + speed *= 0xb0; + + init_cdrom_command(&cgc, NULL, 0); + cgc.cmd[0] = 0xbb; + + /* + * we set read and write time to the same. although a drive + * can typically read much faster than write, this minimizes + * the spin up/down when we write and gather data. if the + * device is opened read only, we never get to here. + */ + cgc.cmd[2] = cgc.cmd[4] = (speed >> 8) & 0xff; + cgc.cmd[3] = cgc.cmd[5] = speed & 0xff; + + return cdi->ops->generic_packet(cdi, &cgc); +} + +int pkt_set_capacity(struct packet_device *pd) +{ + struct cdrom_generic_command cgc; + struct cdrom_device_info *cdi = pd->cdi; + struct cdvd_capacity cap; + int ret; + + init_cdrom_command(&cgc, &cap, sizeof(cap)); + cgc.cmd[0] = GPCMD_READ_CDVD_CAPACITY; + if ((ret = cdi->ops->generic_packet(cdi, &cgc))) + return ret; + + if (cap.lba == 0) { + packet_sizes[pd->pkt_dev] = 65536; + } else { + packet_sizes[pd->pkt_dev] = be32_to_cpu(cap.lba) << 1; + } + printk("packet: %dKB available\n", packet_sizes[pd->pkt_dev]); + return 0; +} + +static inline struct packet_device *pkt_find_dev(kdev_t dev) +{ + int i; + + for (i = 0; i < MAX_WRITERS; i++) { + if (packet_devs[i].dev == dev || packet_devs[i].pkt_dev == MINOR(dev)) + return &packet_devs[i]; + } + + printk("returning NULL pd for %s\n", kdevname(dev)); + return NULL; +} + +/* + * called at open time. return 1 if the device can only be opened read-only. + */ +int pkt_open_dev(struct packet_device *pd) +{ + int ret; + + if ((ret = pkt_probe_settings(pd))) { + DPRINTK("packet: %s failed probe\n", pd->name); + return ret; + } + + if ((ret = pkt_write_settings(pd))) { + DPRINTK("packet: %s failed saving write settings\n", pd->name); + return ret; + } + + /* FIXME: probe drives that can go faster than 4x */ + if ((ret = pkt_set_write_speed(pd, 4))) { + DPRINTK("packet: %s couldn't set write speed\n", pd->name); + return ret; + } + + if ((ret = pkt_set_capacity(pd))) { + DPRINTK("packet: can't read capacity\n"); + return ret; + } + return 0; +} + +/* + * called the device is closed. makes sure that the device flushes + * the internal cache before we close. + */ +void pkt_release_dev(struct packet_device *pd) +{ + if (pkt_flush_cache(pd)) + DPRINTK("packet: %s not flushing cache\n", pd->name); +} + +static int pkt_open(struct inode *inode, struct file *file) +{ + struct packet_device *pd; + int ret = 0; + + MOD_INC_USE_COUNT; + + /* should this really be necessary?? */ + if (!inode) { + ret = -EINVAL; + goto out; + } + + if (MINOR(inode->i_rdev) >= MAX_WRITERS) { + printk("packet: max %d writers supported\n", MAX_WRITERS); + ret = -ENODEV; + goto out; + } + + pd = &packet_devs[MINOR(inode->i_rdev)]; + file->private_data = pd; + if (pd->flags & PACKET_READY) + if ((ret = pkt_open_dev(pd))) + goto out; + + return 0; +out: + MOD_DEC_USE_COUNT; + return ret; +} + +request_queue_t *pkt_get_queue(kdev_t dev) +{ + struct blk_dev_struct *bdev = blk_dev + MAJOR(dev); +#if defined(CONFIG_SMP) + if (!test_bit(0, &io_request_lock)) + printk("queue gotten without lock held!\n"); +#endif + + if (bdev->queue) + return bdev->queue(dev); + else + return &blk_dev[MAJOR(dev)].request_queue; +} + +static int pkt_close(struct inode *inode, struct file *file) +{ + struct packet_device *pd = pkt_find_dev(inode->i_rdev); + + int ret = 0; + + if (pd->dev) + pkt_release_dev(pd); + MOD_DEC_USE_COUNT; + return ret; +} + +static int pkt_new_dev(struct packet_device *pd, kdev_t dev) +{ + struct cdrom_device_info *cdi; + int i; + + for (i = 0; i < MAX_WRITERS; i++) { + if (packet_devs[i].dev == dev) { + printk("packet: %s already setup\n", kdevname(dev)); + return -EBUSY; + } + if (!packet_devs[i].dev) + break; + } + + if (i == MAX_WRITERS) { + printk("packet: max %d writers supported\n", MAX_WRITERS); + return -ENXIO; + } + + cdi = cdrom_find_device(dev); + if (cdi == NULL) { + printk("packet: %s is not a CD-ROM\n", kdevname(dev)); + return -ENXIO; + } + + memset(pd, 0, sizeof(struct packet_device)); + set_blocksize(dev, CD_FRAMESIZE); + pd->cdi = cdi; + pd->dev = dev; + pd->pkt_dev = i; + strncpy(pd->name, cdi->name, sizeof(pd->name) - 1); + spin_lock_init(&pd->lock); + DPRINTK("packet: writer %s sucessfully registered\n", pd->name); + return 0; +} + + +static int pkt_setup_dev(struct packet_device *pd, struct inode *inode, + kdev_t dev) +{ + int ret; + + if (!S_ISBLK(inode->i_mode)) { + printk("packet: CD-ROM writer must be a block device (duh)\n"); + return -ENOTBLK; + } + if (IS_RDONLY(inode)) { + printk("packet: Can't write to read-only dev\n"); + return -EROFS; + } + if ((ret = pkt_new_dev(pd, dev))) { + printk("packet: all booked up\n"); + return ret; + } + pd->flags |= PACKET_READY; + return 0; +} + +static int pkt_remove_dev(struct packet_device *pd) +{ + pd->dev = 0; + pd->cdi = NULL; + pd->flags &= ~PACKET_READY; + DPRINTK("packet: writer %s unregistered\n", pd->name); + MOD_DEC_USE_COUNT; + return 1; +} + +static int pkt_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct packet_device *pd = (struct packet_device *) file->private_data; + + switch (cmd) { + case PACKET_GET_STATS: + if (!pd->dev) { + printk("packet: dev not setup\n"); + return -ENXIO; + } + if (copy_to_user(&arg, &pd->stats, sizeof(struct packet_stats))) + return -EFAULT; + + case PACKET_SET_DEV: + if (pd->dev) { + printk("packet: dev already setup\n"); + return -EBUSY; + } + return pkt_setup_dev(pd, inode, (kdev_t) arg); + + case PACKET_DEL_DEV: + if (!pd->dev) { + printk("packet: dev not setup\n"); + return -ENXIO; + } + return pkt_remove_dev(pd); + + case BLKGETSIZE: + if (!pd->dev) { + printk("packet: dev not setup\n"); + return -ENXIO; + } + return put_user(blk_size[PACKET_MAJOR][MINOR(inode->i_rdev)] << 1, (long *)arg); + + case BLKROSET: + case BLKROGET: + case BLKSSZGET: + if (!pd->dev) { + printk("packet: dev not setup\n"); + return -ENXIO; + } + return blk_ioctl(inode->i_rdev, cmd, arg); + + default: + printk("packet: Unknown ioctl for %x (%x)\n", pd->dev, cmd); + return -ENOTTY; + } + return 0; +} + + +/* + * shows requests in the device queue --- just a debugging thing + */ +#if 0 +static void pkt_show_requests(request_queue_t *q, int max) +{ + struct request *rq = q->current_request; + struct buffer_head *bh; + int i = 0; + + for (rq = q->current_request; rq && (i < max); rq = rq->next, i++) { + printk("rq %lu (in %lu) at %lu\n", rq->nr_sectors, + rq->current_nr_sectors, + rq->sector); + bh = rq->bh; + while (bh) { + printk("cluster at %lu (%u)\n", bh->b_rsector, bh->b_size); + bh = bh->b_reqnext; + } + } +} +#endif + + + +/* + * The following three functions are the plugins to the ll_rw_blk + * layer and decides whether a given request / buffer head can be + * merged. We differ in a couple of ways from "normal" block + * devices: + * + * - don't merge when the buffer / request crosses a packet block + * boundary + * - merge buffer head even though it can't be added directly to the + * front or back of the list. this gives us better performance, since + * what would otherwise require multiple requests can now be handled + * in one. + * - we only care about write merging, reads use device original defaults. + * + * The device original merge_ functions are stored in the packet device + * queue (pd->q) + * + */ +static int pkt_merge_fn(request_queue_t *q, struct request *rq, + struct buffer_head *bh) +{ + struct packet_device *pd = pkt_find_dev(rq->rq_dev); + int span = pd->settings.size; + + /* + * dev might not be setup yet, so check span + */ + if (span) { + if (ZONE(rq->sector, span) != ZONE(bh->b_rsector, span)) + return 0; + } + + return 1; +} + +/* + * rules similar to above + */ +static int pkt_merge_requests_fn(request_queue_t *q, struct request *rq, + struct request *next) +{ + struct packet_device *pd = pkt_find_dev(rq->rq_dev); + int span = pd->settings.size; + + if (span) { + if (ZONE(rq->sector, span) != ZONE(next->sector + next->nr_sectors, span)) + return 0; + } + + return 1; +} + +static int pkt_ll_merge_bh_fn(struct request *rq, struct buffer_head *bh) +{ + if (rq->sector + rq->nr_sectors == bh->b_rsector) { + rq->bhtail->b_reqnext = bh; + rq->bhtail = bh; + rq->nr_sectors += bh->b_size >> 9; + return 1; + } + if ((rq->sector - (bh->b_size >> 9)) == bh->b_rsector) { + bh->b_reqnext = rq->bh; + rq->bh = bh; + rq->buffer = bh->b_data; + rq->current_nr_sectors = bh->b_size >> 9; + rq->sector = bh->b_rsector; + rq->nr_sectors += bh->b_size >> 9; + return 1; + } + return 0; +} + +#define BH_IN_ORDER(b1, b2) ((b1)->b_rsector < (b2)->b_rsector) + +static int pkt_merge_bh_fn(struct request *rq, struct buffer_head *bh) +{ + struct buffer_head *tmp; + + if (pkt_ll_merge_bh_fn(rq, bh)) + return 1; + + /* holes only supported for writing */ + if (rq->cmd == READ) + return 0; + + /* stuff in front? */ + if (bh->b_rsector < rq->sector) { + bh->b_reqnext = rq->bh; + rq->bh = bh; + rq->sector = bh->b_rsector; + rq->current_nr_sectors = bh->b_size >> 9; + goto out; + } + + /* stuff in back? */ + if (bh->b_rsector > rq->bhtail->b_rsector) { + rq->bhtail->b_reqnext = bh; + rq->bhtail = bh; + goto out; + } + + /* find sweet spot */ + for (tmp = rq->bh; tmp->b_reqnext; tmp = tmp->b_reqnext) + if (BH_IN_ORDER(tmp, bh) && BH_IN_ORDER(bh, tmp->b_reqnext)) + break; + bh->b_reqnext = tmp->b_reqnext; + tmp->b_reqnext = bh; +out: + rq->buffer = rq->bh->b_data; + rq->nr_sectors += bh->b_size >> 9; + rq->nr_segments++; + return 1; +} + + +/* + * Remap current request to a new location. Needs to "discuss" these + * things with UDF. + */ +void pkt_remap_write(kdev_t dev) +{ + struct buffer_head *bh; + request_queue_t *q; + + /* FIXME: bh should probably be marked BH_Protected so that + * they are kept in the cache until a write is ended. Then + * we can quickly get ahold of them again and resubmit a + * write to a new location + */ + q = pkt_get_queue(dev); + bh = q->current_request->bh; + + /* release buffers */ + while (bh) { + /* + * FIXME: should be 0, but for now we don't want any + * resubmissions + */ + mark_buffer_uptodate(bh, 1); + unlock_buffer(bh); + bh = bh->b_reqnext; + } + q->current_request = q->current_request->next; +} + +/* + * we use this as our default b_end_io handler, since we need to take + * the entire request off the list if just on of the clusters fail. + * later one this should also talk to UDF about relocating blocks -- for + * now we just drop the rq entirely. when doing the relocating we must also + * lock the bh down to ensure that we can easily reconstruct the write should + * it fail. + */ +static void pkt_end_io_write(struct buffer_head *bh, int uptodate) +{ + struct packet_device *pd = pkt_find_dev(bh->b_dev); + + if (!uptodate) { + pkt_remap_write(bh->b_dev); + return; + } +#if 0 + if ((bh->b_rsector > pd->lra) + pd->lra = bh->b_rsector; +#endif + VPRINTK("ended bh %lu\n", bh->b_rsector); + mark_buffer_uptodate(bh, uptodate); + unlock_buffer(bh); + if (bh->b_dev_id == pkt_end_io_write) { + bh->b_dev_id = NULL; + brelse(bh); + } + pd->stats.bh_e++; +} + +static void pkt_show_stats(kdev_t dev) +{ + struct packet_device *pd = pkt_find_dev(dev); + + printk("BH: started (%lu) ended (%lu)\n", pd->stats.bh_s, pd->stats.bh_e); +} + +/* + * replace b_end_io with our own, so that we can keep bhs in cache for + * the duration of the entire write. + */ +static void pkt_init_bh(struct request *rq) +{ + struct buffer_head *bh; + unsigned cnt = 0; + + bh = rq->bh; + while (bh) { + /* FIXME */ + if (bh->b_end_io == end_buffer_io_async) + panic("woops, page cache...\n"); + bh->b_end_io = pkt_end_io_write; + if (!buffer_uptodate(bh) && bh->b_dev_id != pkt_end_io_write) + printk("that's why?!\n"); + bh = bh->b_reqnext; + cnt += rq->current_nr_sectors; + } + if (cnt != rq->nr_sectors) { + pkt_show_stats(rq->rq_dev); + show_buffers(); + spin_unlock_irq(&io_request_lock); + panic("botched request %u (%lu)\n", cnt, rq->nr_sectors); + } +} + +static void pkt_add_stats(struct packet_device *pd, int read, int written, int bs) +{ + pd->stats.bh_s += (written / bs); + pd->stats.blocks_written += written; + pd->stats.blocks_read += read; +} + +static void pkt_show_bhstring(struct buffer_head *bh) +{ + int i = 0; + + while (bh && i < 128) { + DPRINTK("bh at %lu\n", bh->b_rsector); + bh = bh->b_reqnext; + i++; + } + DPRINTK("%u bhs in all\n", i); +} + +/* + * does request span two packets? 0 == yes, 1 == no + */ +static inline int pkt_same_zone(struct packet_device *pd, struct request *rq) +{ + int span = pd->settings.size; + + /* debug stuff */ + if (span == 0) + panic("packet size WRONG for pd %s!\n", pd->name); + + if (ZONE(rq->sector, span) != ZONE(rq->sector + rq->nr_sectors-1, span)) + return 0; + + return 1; +} + +/* + * Add the request queue to the list. Should already be plugged, otherwise + * we wouldn't have gotten the request. + */ +static inline void pkt_schedule_queue(request_queue_t *q) +{ + if (q->plugged) { + q->plugged = 0; + if (q->current_request) + q->request_fn(q); + } +} + +static inline void pkt_plug_queue(request_queue_t *q) +{ + q->plugged = 1; + queue_task(&q->plug_tq, &tq_disk); +} + +/* + * Put rq in the queue for device + */ +static void pkt_queue_rq(request_queue_t *q, struct request *rq) +{ + struct request *tmp; + + rq->next = NULL; + + if (q->current_request == NULL) { + pkt_plug_queue(q); + q->current_request = rq; + pkt_schedule_queue(q); + return; + } + + tmp = q->current_request; + while (tmp->next) + tmp = tmp->next; + + tmp->next = rq; + pkt_schedule_queue(q); +} + +/* + * basically just does a ll_rw_block for the bhs given to use, but we + * don't return until we have them. + */ +static void pkt_read_bhlist(struct packet_device *pd, + struct buffer_head *bhlist[], int count) +{ + struct buffer_head *bh; + int i; + + ll_rw_block(READ, count, bhlist); + for (i = 0; i < count; i++) { + bh = bhlist[i]; + /* zero blocks that haven't been written yet */ +#if 0 + if (pd->flags & PACKET_LRA_VALID && (bh->b_rsector < pd->lra)) { + memset(bh->b_data, 0, bh->b_size); + continue; + } +#endif + if (!(buffer_uptodate(bh))) { + VPRINTK("waiting on buffer %lu\n", bh->b_rsector); + wait_on_buffer(bh); + } + } +} + +static void pkt_gather_data(struct packet_device *pd, struct request *rq) +{ + unsigned long start_s, end_s, sector; + unsigned int sectors, ss, bs, i; + struct buffer_head *bh, *bhlist[PACKET_MAX_SIZE]; + + /* + * all calculations are done with 512 byte sectors. block size is + * set to 2048 for all CD-ROM's, but I still get the occasional + * 1024 cluster... + */ + sectors = pd->settings.size - rq->nr_sectors; + start_s = rq->sector - (rq->sector % pd->settings.size); + end_s = start_s + pd->settings.size; + + /* + * ss == sectors per bh, bs == size of bh + */ + ss = rq->current_nr_sectors; + bs = rq->bh->b_size; + + VPRINTK("need %d sectors for %s\n", sectors, kdevname(pd->dev)); + VPRINTK("from %lu to %lu (%lu - %lu)\n", start_s, end_s, rq->bh->b_rsector, rq->bhtail->b_rsector + rq->current_nr_sectors); + + ASSERT(rq->sector == rq->bh->b_rsector); + + /* got front hole, if any */ + spin_lock(&pd->lock); + spin_unlock_irq(&io_request_lock); + sector = rq->sector; + if (sector > start_s) { + int cnt; + cnt = (sector - start_s) / ss; + sector = start_s; +#if PACKET_DEBUG > 1 + DPRINTK("get %u bhs at front (%lu)\n", cnt, sector); +#endif + for (i = 0; i < cnt; i++) { + bhlist[i] = getblk(pd->dev, sector / ss, bs); + bhlist[i]->b_dev_id = pkt_end_io_write; + rq->nr_sectors += ss; + rq->nr_segments++; + sector += ss; + } + VPRINTK("block now %lu (%lu)\n", sector, sector / ss); + pkt_read_bhlist(pd, bhlist, cnt); + /* link them (pkt_read_bhlist screws them up) */ + for (i = 0; i < cnt; i++) + bhlist[i]->b_reqnext = bhlist[i + 1]; + bhlist[cnt - 1]->b_reqnext = rq->bh; + bh = rq->bh; + rq->bh = bhlist[0]; + rq->buffer = rq->bh->b_data; +#if PACKET_DEBUG > 1 + pkt_show_bhstring(rq->bh); +#endif + } else { + bh = rq->bh; + } + + /* walk the rest and get the chunks we are missing */ + VPRINTK("traversing rest of list %lu %lu\n", sector, sector / ss); +#if PACKET_DEBUG > 1 + pkt_show_bhstring(rq->bh); +#endif + for (sector += ss; sector < end_s; sector += ss) { + struct buffer_head *foo_bh; + /* next bh is in extension of this one */ + if (bh->b_reqnext) { + if (NEXT_BH(bh, bh->b_reqnext)) { + bh = bh->b_reqnext; + VPRINTK("no hole at %lu\n", bh->b_rsector); + continue; + } + VPRINTK("hole at %lu (%lu)\n", bh->b_rsector, bh->b_reqnext->b_rsector); + } + foo_bh = getblk(pd->dev, sector / ss, bs); + foo_bh->b_dev_id = pkt_end_io_write; + pkt_read_bhlist(pd, &foo_bh, 1); + VPRINTK("got block %lu\n", foo_bh->b_rsector); + if (bh->b_reqnext) + foo_bh->b_reqnext = bh->b_reqnext; + bh->b_reqnext = foo_bh; + bh = foo_bh; + rq->nr_sectors += ss; + rq->nr_segments++; + } +#if PACKET_DEBUG > 1 + pkt_show_bhstring(rq->bh); +#endif + bh->b_reqnext = NULL; + rq->bhtail = bh; + rq->buffer = rq->bh->b_data; + VPRINTK("unlocked last %lu\n", rq->bhtail->b_rsector); + + rq->sector = start_s; + rq->cmd = WRITE_PACKET; + spin_unlock(&pd->lock); + spin_lock_irq(&io_request_lock); + pkt_init_bh(rq); + pkt_add_stats(pd, sectors, rq->nr_sectors, rq->current_nr_sectors); + + /* sanity check */ + if (rq->nr_sectors != pd->settings.size) { + pkt_show_bhstring(rq->bh); + panic("packet: request mismatch %lu (should be %u)\n", + rq->nr_sectors, + pd->settings.size); + } +} + +static void pkt_request(request_queue_t *q) +{ + struct packet_device *pd; + struct request *rq = q->current_request; + request_queue_t *pdq; + + pd = pkt_find_dev(rq->rq_dev); + pdq = pkt_get_queue(pd->dev); + + /* unplug device to flush outstanding requests */ + spin_unlock_irq(&io_request_lock); + generic_unplug_device(pdq); + spin_lock_irq(&io_request_lock); + + /* + * just ship reads directly to the corresponding device, we don't + * care about those + */ + if (rq->cmd == READ) { + q->current_request = rq->next; + /* why is this necessary? */ + if (rq->next) + pkt_plug_queue(q); + pkt_queue_rq(pdq, rq); + return; + } + + /* paranoia... */ + if (!pkt_same_zone(pd, rq)) { + printk("rq %lu to %lu\n", rq->sector, rq->nr_sectors); + printk("bh %lu to %lu\n", rq->bh->b_rsector, rq->bhtail->b_rsector); + panic("merging is wrong\n"); + } + + /* + * perfect match. the merge_ functions have already made sure that + * a request doesn't cross a packet boundary, so if the sector + * count matches it's good. + */ + if (rq->nr_sectors == pd->settings.size) { + q->current_request = rq->next; + /* why is this necessary? */ + if (rq->next) + pkt_plug_queue(q); + rq->cmd = WRITE_PACKET; + pkt_init_bh(rq); + pkt_queue_rq(pdq, rq); + return; + } + + /* paranoia... */ + if (rq->nr_sectors > pd->settings.size) + panic("packet: request too big! BUG! %lu\n", rq->nr_sectors); + + /* + * we get this far -- this means that data is lacking before we + * can submit a packet write request. + */ + pkt_gather_data(pd, rq); + q->current_request = rq->next; + if (rq->next) + pkt_plug_queue(q); + pkt_queue_rq(pdq, rq); +} + +/* open and release is just for handling ioctls */ +static struct block_device_operations packet_ops = { + open: pkt_open, + release: pkt_close, + ioctl: pkt_ioctl, +}; + +int pkt_init(void) +{ + request_queue_t *q; + int ret; + + q = BLK_DEFAULT_QUEUE(PACKET_MAJOR); + blk_init_queue(q, pkt_request); + q->merge_fn = pkt_merge_fn; + q->merge_requests_fn = pkt_merge_requests_fn; + q->merge_bh_fn = pkt_merge_bh_fn; + + if (register_blkdev(PACKET_MAJOR, "packet", &packet_ops)) { + printk("unable to register packet device\n"); + return -EIO; + } + ret = -ENOMEM; + packet_sizes = kmalloc(MAX_WRITERS * sizeof(int), GFP_KERNEL); + if (packet_sizes == NULL) + goto out; + + packet_blksize = kmalloc(MAX_WRITERS * sizeof(int), GFP_KERNEL); + if (packet_blksize == NULL) + goto out; + + packet_devs = kmalloc(MAX_WRITERS * sizeof(struct packet_device), GFP_KERNEL); + if (packet_devs == NULL) + goto out; + + memset(packet_devs, 0, MAX_WRITERS * sizeof(struct packet_device)); + memset(packet_sizes, 0, MAX_WRITERS * sizeof(int)); + memset(packet_blksize, 0, MAX_WRITERS * sizeof(int)); + + blk_size[PACKET_MAJOR] = packet_sizes; + blksize_size[PACKET_MAJOR] = packet_blksize; + set_blocksize(MKDEV(PACKET_MAJOR, 0), CD_FRAMESIZE); + + DPRINTK("packet: %s\n", VERSION_CODE); + return 0; + +out: + unregister_blkdev(PACKET_MAJOR, "packet"); + if (packet_devs) + kfree(packet_devs); + if (packet_sizes) + kfree(packet_sizes); + if (packet_blksize) + kfree(packet_blksize); + return ret; +} + +void __exit pkt_exit(void) +{ + unregister_blkdev(PACKET_MAJOR, "packet"); + blk_cleanup_queue(BLK_DEFAULT_QUEUE(PACKET_MAJOR)); + kfree(packet_sizes); + kfree(packet_blksize); + kfree(packet_devs); +} + +module_init(pkt_init); +module_exit(pkt_exit); diff -urN --exclude-from exclude-from linux-2.3.43-clean/drivers/cdrom/cdrom.c linux-2.3.43/drivers/cdrom/cdrom.c --- linux-2.3.43-clean/drivers/cdrom/cdrom.c Tue Feb 1 15:44:54 2000 +++ linux-2.3.43/drivers/cdrom/cdrom.c Thu Feb 10 21:11:58 2000 @@ -187,14 +187,23 @@ -- Fixed CDDA ripping with cdda2wav - accept much larger requests of number of frames and split the reads in blocks of 8. - 3.05 Dec 13, 1999 - Jens Axboe + 3.06 Dec 13, 1999 - Jens Axboe -- Added support for changing the region of DVD drives. -- Added sense data to generic command. + + 3.07 Feb 2, 2000 - Jens Axboe + -- Do same "read header length" trick in cdrom_get_disc_info() as + we do in cdrom_get_track_info() -- some drive don't obbey specs and + fail if they can't supply the full Mt Fuji size table. + -- Deleted stuff related to setting up write modes. It has a different + home now. + -- Clear header length in mode_select unconditionally. + -- Removed the register_disk() that was added, not needed here. -------------------------------------------------------------------------*/ -#define REVISION "Revision: 3.06" -#define VERSION "Id: cdrom.c 3.06 1999/12/13" +#define REVISION "Revision: 3.07" +#define VERSION "Id: cdrom.c 3.07 2000/02/02" /* I use an error-log mask to give fine grain control over the type of messages dumped to the system logs. The available masks include: */ @@ -386,7 +395,6 @@ return 0; } -static struct cdrom_device_info *cdrom_find_device(kdev_t dev) { struct cdrom_device_info *cdi; @@ -1285,7 +1293,7 @@ struct cdrom_device_ops *cdo = cdi->ops; memset(cgc->cmd, 0, sizeof(cgc->cmd)); - + memset(cgc->buffer, 0, 2); cgc->cmd[0] = GPCMD_MODE_SELECT_10; cgc->cmd[1] = 0x10; /* PF */ cgc->cmd[7] = cgc->buflen >> 8; @@ -1960,9 +1968,6 @@ buffer[offset+13] = volctrl.channel2 & mask[offset+13]; buffer[offset+15] = volctrl.channel3 & mask[offset+15]; - /* clear the first three */ - memset(buffer, 0, 3); - /* set volume */ cgc.buffer = buffer; return cdrom_mode_select(cdi, &cgc); @@ -2061,7 +2066,7 @@ if (copy && !ret) __copy_to_user(userbuf, cgc.buffer, cgc.buflen); /* copy back sense data */ - if (ret && sense != NULL) + if (sense != NULL) if (copy_to_user(sense, cgc.sense, sizeof(struct request_sense))) ret = -EFAULT; kfree(cgc.buffer); @@ -2116,12 +2121,26 @@ struct cdrom_device_info *cdi = cdrom_find_device(dev); struct cdrom_device_ops *cdo = cdi->ops; struct cdrom_generic_command cgc; + int ret; /* set up command and get the disc info */ init_cdrom_command(&cgc, di, sizeof(*di)); cgc.cmd[0] = GPCMD_READ_DISC_INFO; - cgc.cmd[8] = cgc.buflen; + cgc.cmd[8] = cgc.buflen = 2; + if ((ret = cdo->generic_packet(cdi, &cgc))) + return ret; + + /* not all drives have the same disc_info length, so requeue + * packet with the length the drive tells us it can supply + */ + cgc.buflen = be16_to_cpu(di->disc_information_length) + + sizeof(di->disc_information_length); + + if (cgc.buflen > sizeof(disc_information)) + cgc.buflen = sizeof(disc_information); + + cgc.cmd[8] = cgc.buflen; return cdo->generic_packet(cdi, &cgc); } @@ -2236,6 +2255,7 @@ EXPORT_SYMBOL(cdrom_mode_select); EXPORT_SYMBOL(cdrom_mode_sense); EXPORT_SYMBOL(init_cdrom_command); +EXPORT_SYMBOL(cdrom_find_device); #ifdef CONFIG_SYSCTL --- linux-2.3.43-clean/drivers/scsi/scsi_lib.c Thu Feb 10 06:41:50 2000 +++ linux-2.3.43/drivers/scsi/scsi_lib.c Thu Feb 10 06:38:29 2000 @@ -810,10 +810,11 @@ if ((SHpnt->can_queue > 0 && (SHpnt->host_busy >= SHpnt->can_queue)) || (SHpnt->host_blocked)) { /* - * If we are unable to process any commands at all for this - * device, then we consider it to be starved. What this means - * is that there are no outstanding commands for this device - * and hence we need a little help getting it started again + * If we are unable to process any commands at all for + * this device, then we consider it to be starved. + * What this means is that there are no outstanding + * commands for this device and hence we need a + * little help getting it started again * once the host isn't quite so busy. */ if (SDpnt->device_busy == 0) { @@ -899,8 +900,8 @@ } /* * If so, we are ready to do something. Bump the count - * while the queue is locked and then break out of the loop. - * Otherwise loop around and try another request. + * while the queue is locked and then break out of the + * loop. Otherwise loop around and try another request. */ if (!SCpnt) { break; @@ -929,8 +930,9 @@ memcpy(&SCpnt->request, req, sizeof(struct request)); /* - * We have copied the data out of the request block - it is now in - * a field in SCpnt. Release the request block. + * We have copied the data out of the request block - + * it is now in a field in SCpnt. Release the request + * block. */ req->next = NULL; req->rq_status = RQ_INACTIVE; @@ -949,12 +951,14 @@ /* * This will do a couple of things: * 1) Fill in the actual SCSI command. - * 2) Fill in any other upper-level specific fields (timeout). + * 2) Fill in any other upper-level specific fields + * (timeout). * - * If this returns 0, it means that the request failed (reading - * past end of disk, reading offline device, etc). This won't - * actually talk to the device, but some kinds of consistency - * checking may cause the request to be rejected immediately. + * If this returns 0, it means that the request failed + * (reading past end of disk, reading offline device, + * etc). This won't actually talk to the device, but + * some kinds of consistency checking may cause the + * request to be rejected immediately. */ if (STpnt == NULL) { STpnt = scsi_get_request_dev(req); @@ -997,8 +1001,8 @@ scsi_dispatch_cmd(SCpnt); /* - * Now we need to grab the lock again. We are about to mess with - * the request queue and try to find another command. + * Now we need to grab the lock again. We are about to mess + * with the request queue and try to find another command. */ spin_lock_irq(&io_request_lock); } diff -urN --exclude-from exclude-from linux-2.3.43-clean/drivers/scsi/sr.c linux-2.3.43/drivers/scsi/sr.c --- linux-2.3.43-clean/drivers/scsi/sr.c Thu Feb 10 06:41:50 2000 +++ linux-2.3.43/drivers/scsi/sr.c Thu Feb 10 23:15:10 2000 @@ -23,6 +23,9 @@ * Modified by Jens Axboe - Uniform sr_packet() * interface, capabilities probe additions, ioctl cleanups, etc. * + * Modified by Jens Axboe - support packet writing + * through generic packet layer. + * */ #include @@ -74,7 +77,7 @@ finish:sr_finish, attach:sr_attach, detach:sr_detach, - init_command:sr_init_command + init_command:sr_init_command, }; Scsi_CD *scsi_CDs = NULL; @@ -233,6 +236,11 @@ scsi_CDs[device_nr].capacity - error_sector < 4 * 75) sr_sizes[device_nr] = error_sector >> 1; } + + if (SCpnt->request.cmd == WRITE) { + printk("ignoring scsi_io_completion for write\n"); + return; + } /* * This calls the generic completion function, now that we know * how many actual sectors finished, and how many sectors we need @@ -296,9 +304,6 @@ else printk("sr: can't switch blocksize: in interrupt\n"); } - if (SCpnt->request.cmd == WRITE) { - return 0; - } if (scsi_CDs[dev].device->sector_size == 1024) { if ((block & 1) || (SCpnt->request.nr_sectors & 1)) { printk("sr.c:Bad 1K block number requested (%d %ld)", @@ -320,12 +325,16 @@ } } switch (SCpnt->request.cmd) { - case WRITE: + case WRITE_PACKET: + printk("sr: got WRITE_PACKET\n"); + SCpnt->cmnd[0] = WRITE_10; + break; + case WRITE: { if (!scsi_CDs[dev].device->writeable) { return 0; } SCpnt->cmnd[0] = WRITE_10; - break; + } case READ: SCpnt->cmnd[0] = READ_10; break; @@ -623,7 +632,6 @@ /*else I don't think it can close its tray scsi_CDs[i].cdi.mask |= CDC_CLOSE_TRAY; */ - scsi_free(buffer, 512); } @@ -731,6 +739,7 @@ { int i; char name[6]; + struct cdrom_device_info *cdi; blk_dev[MAJOR_NR].queue = sr_find_queue; blk_size[MAJOR_NR] = sr_sizes; @@ -757,17 +766,18 @@ scsi_CDs[i].readcd_cdda = 0; sr_sizes[i] = scsi_CDs[i].capacity >> (BLOCK_SIZE_BITS - 9); - scsi_CDs[i].cdi.ops = &sr_dops; - scsi_CDs[i].cdi.handle = &scsi_CDs[i]; - scsi_CDs[i].cdi.dev = MKDEV(MAJOR_NR, i); - scsi_CDs[i].cdi.mask = 0; - scsi_CDs[i].cdi.capacity = 1; + cdi = &scsi_CDs[i].cdi; + cdi->ops = &sr_dops; + cdi->handle = &scsi_CDs[i]; + cdi->dev = MKDEV(MAJOR_NR, i); + cdi->mask = 0; + cdi->capacity = 1; get_capabilities(i); sr_vendor_init(i); sprintf(name, "sr%d", i); - strcpy(scsi_CDs[i].cdi.name, name); - register_cdrom(&scsi_CDs[i].cdi); + strcpy(cdi->name, name); + register_cdrom(cdi); } @@ -791,6 +801,7 @@ if (cpnt->device == SDp) { kdev_t devi = MKDEV(MAJOR_NR, i); struct super_block *sb = get_super(devi); + struct cdrom_device_info *cdi; /* * Since the cdrom is read-only, no need to sync the device. @@ -801,10 +812,11 @@ invalidate_buffers(devi); /* - * Reset things back to a sane state so that one can re-load a new - * driver (perhaps the same one). + * Reset things back to a sane state so that one can + * re-load a new driver (perhaps the same one). */ - unregister_cdrom(&(cpnt->cdi)); + cdi = &(cpnt->cdi); + unregister_cdrom(cdi); cpnt->device = NULL; cpnt->capacity = 0; SDp->attached--; diff -urN --exclude-from exclude-from linux-2.3.43-clean/fs/buffer.c linux-2.3.43/fs/buffer.c --- linux-2.3.43-clean/fs/buffer.c Fri Feb 11 00:53:35 2000 +++ linux-2.3.43/fs/buffer.c Fri Feb 11 02:21:06 2000 @@ -725,7 +725,7 @@ bh->b_dev_id = dev_id; } -static void end_buffer_io_sync(struct buffer_head *bh, int uptodate) +void end_buffer_io_sync(struct buffer_head *bh, int uptodate) { mark_buffer_uptodate(bh, uptodate); unlock_buffer(bh); @@ -738,7 +738,7 @@ BUG(); } -static void end_buffer_io_async(struct buffer_head * bh, int uptodate) +void end_buffer_io_async(struct buffer_head * bh, int uptodate) { static spinlock_t page_uptodate_lock = SPIN_LOCK_UNLOCKED; unsigned long flags; diff -urN --exclude-from exclude-from linux-2.3.43-clean/include/linux/blkdev.h linux-2.3.43/include/linux/blkdev.h --- linux-2.3.43-clean/include/linux/blkdev.h Tue Feb 8 22:59:20 2000 +++ linux-2.3.43/include/linux/blkdev.h Fri Feb 11 05:44:03 2000 @@ -48,6 +48,7 @@ typedef void (make_request_fn) (int rw, struct buffer_head *bh); typedef void (plug_device_fn) (request_queue_t *q, kdev_t device); typedef void (unplug_device_fn) (void *q); +typedef int (merge_bh_fn) (struct request *req, struct buffer_head *bh); struct request_queue { @@ -55,6 +56,7 @@ request_fn_proc * request_fn; merge_request_fn * merge_fn; merge_requests_fn * merge_requests_fn; + merge_bh_fn * merge_bh_fn; make_request_fn * make_request_fn; plug_device_fn * plug_device_fn; /* diff -urN --exclude-from exclude-from linux-2.3.43-clean/include/linux/cdrom.h linux-2.3.43/include/linux/cdrom.h --- linux-2.3.43-clean/include/linux/cdrom.h Tue Feb 1 15:45:00 2000 +++ linux-2.3.43/include/linux/cdrom.h Thu Feb 10 21:12:10 2000 @@ -789,6 +789,7 @@ int page_code, int page_control); extern void init_cdrom_command(struct cdrom_generic_command *cgc, void *buffer, int len); +extern struct cdrom_device_info *cdrom_find_device(kdev_t dev); typedef struct { __u16 disc_information_length; @@ -796,9 +797,9 @@ __u8 reserved1 : 3; __u8 erasable : 1; __u8 border_status : 2; - __u8 disc_border : 2; + __u8 disc_status : 2; #elif defined(__LITTLE_ENDIAN_BITFIELD) - __u8 disc_border : 2; + __u8 disc_status : 2; __u8 border_status : 2; __u8 erasable : 1; __u8 reserved1 : 3; @@ -981,7 +982,7 @@ #endif __u8 session_format; __u8 reserved6; - __u32 packet_size; + __u32 packet_size __attribute__((packed)); __u16 audio_pause; __u8 mcn[16]; __u8 isrc[16]; diff -urN --exclude-from exclude-from linux-2.3.43-clean/include/linux/fs.h linux-2.3.43/include/linux/fs.h --- linux-2.3.43-clean/include/linux/fs.h Fri Feb 11 00:53:35 2000 +++ linux-2.3.43/include/linux/fs.h Fri Feb 11 05:44:02 2000 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -64,6 +65,7 @@ #define WRITE 1 #define READA 2 /* read-ahead - don't block if no resources */ #define SPECIAL 4 /* For non-blockdevice requests in request queue */ +#define WRITE_PACKET 5 /* for packet writers */ #define WRITERAW 5 /* raw write - don't play with buffer lists */ diff -urN --exclude-from exclude-from linux-2.3.43-clean/include/linux/packet.h linux-2.3.43/include/linux/packet.h --- linux-2.3.43-clean/include/linux/packet.h Thu Jan 1 01:00:00 1970 +++ linux-2.3.43/include/linux/packet.h Fri Feb 11 05:47:54 2000 @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2000 Jens Axboe + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + * Packet writing layer for ATAPI and SCSI CD-R, CD-RW, DVD-R, and + * DVD-RW devices. + * + */ + +#ifndef PACKET_H +#define PACKET_H + +/* + * device types + */ +#define PACKET_CDR 1 +#define PACKET_CDRW 2 +#define PACKET_DVDR 3 +#define PACKET_DVDRW 4 + +/* + * flags + */ +#define PACKET_WRITEABLE 1 +#define PACKET_NWA_VALID 2 +#define PACKET_LRA_VALID 4 +#define PACKET_READY 5 + +/* + * Disc status -- from READ_DISC_INFO + */ +#define PACKET_DISC_EMPTY 0 +#define PACKET_DISC_INCOMPLETE 1 +#define PACKET_DISC_COMPLETE 2 +#define PACKET_DISC_OTHER 3 + +/* + * Last session/border status + */ +#define PACKET_SESSION_EMPTY 0 +#define PACKET_SESSION_INCOMPLETE 1 +#define PACKET_SESSION_RESERVED 2 +#define PACKET_SESSION_COMPLETE 3 + +struct packet_stats { + unsigned long bh_s; + unsigned long bh_e; + unsigned long blocks_written; + unsigned long blocks_read; +}; + +/* + * packet ioctls + */ +#define PACKET_GET_STATS _IOR('X', 0, struct packet_stats) +#define PACKET_SET_DEV _IOW('X', 1, unsigned long) +#define PACKET_DEL_DEV _IOW('X', 2, unsigned long) + +#ifdef __KERNEL__ +#include + +struct packet_settings { + __u8 size; /* packet size in frames */ + __u8 fp; /* fixed packets */ + __u8 link_loss; /* the rest is specified + * as per Mt Fuji */ + __u8 write_type; + __u8 track_mode; + __u8 block_mode; +}; + +struct packet_device { + kdev_t dev; /* dev attached */ + kdev_t pkt_dev; /* our dev */ + char name[6]; + struct cdrom_device_info *cdi; /* cdrom matching dev */ + struct packet_settings settings; + struct packet_stats stats; + __u8 type; + __u32 flags; + __u8 disc_status; + __u8 track_status; /* last one */ + __u32 nwa; /* next writable address */ + __u32 lra; /* last recorded address */ + spinlock_t lock; +}; + +struct cdvd_capacity { + __u32 lba; + __u32 block_length; +}; + +#endif /* __KERNEL__ */ + +#endif /* PACKET_H */ diff -urN --exclude-from exclude-from linux-2.3.43-clean/kernel/ksyms.c linux-2.3.43/kernel/ksyms.c --- linux-2.3.43-clean/kernel/ksyms.c Fri Feb 11 00:53:35 2000 +++ linux-2.3.43/kernel/ksyms.c Fri Feb 11 07:05:20 2000 @@ -177,6 +177,7 @@ EXPORT_SYMBOL(get_hardblocksize); EXPORT_SYMBOL(set_blocksize); EXPORT_SYMBOL(getblk); +EXPORT_SYMBOL(show_buffers); EXPORT_SYMBOL(bread); EXPORT_SYMBOL(breada); EXPORT_SYMBOL(__brelse); @@ -226,6 +227,12 @@ EXPORT_SYMBOL(page_follow_link); EXPORT_SYMBOL(page_symlink_inode_operations); EXPORT_SYMBOL(block_symlink); + +extern void end_buffer_io_async(struct buffer_head *bh, int uptodate); +extern void end_buffer_io_sync(struct buffer_head *bh, int uptodate); + +EXPORT_SYMBOL(end_buffer_io_async); +EXPORT_SYMBOL(end_buffer_io_sync); /* for stackable file systems (lofs, wrapfs, etc.) */ EXPORT_SYMBOL(add_to_page_cache);