diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.2.18-pre17/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c --- /opt/kernel/linux-2.2.18-pre17/drivers/block/ide-cd.c Tue Oct 24 14:42:58 2000 +++ linux/drivers/block/ide-cd.c Tue Oct 24 15:30:04 2000 @@ -285,9 +285,11 @@ * 4.58 May 1, 2000 - Clean up ACER50 stuff. * - Fix small problem with ide_cdrom_capacity * + * 4.99 - Added write support for packet writing. + * *************************************************************************/ -#define IDECD_VERSION "4.58" +#define IDECD_VERSION "4.99" #include #include @@ -324,7 +326,6 @@ info->nsectors_buffered = 0; } - static void cdrom_analyze_sense_data(ide_drive_t *drive, struct packet_command *failed_command, @@ -348,6 +349,9 @@ return; } + if (failed_command->quiet) + return; + if (sense->error_code == 0x70 && sense->sense_key == 0x02 && ((sense->asc == 0x3a && sense->ascq == 0x00) || (sense->asc == 0x04 && sense->ascq == 0x01))) @@ -360,6 +364,15 @@ return; } + /* + * If a read toc is executed for a CD-R or CD-RW medium where + * the first toc has not been recorded yet, it will fail with + * 05/24/00 + */ + if (failed_command && failed_command->c[0] == GPCMD_READ_TOC_PMA_ATIP) + if (sense->sense_key == 0x05 && sense->asc == 0x24) + return; + #if VERBOSE_IDE_CD_ERRORS { int i; @@ -524,8 +537,10 @@ (struct packet_command *) pc->sense, (struct request_sense *) (pc->buffer - pc->c[4])); } - if (rq->cmd == READ && !rq->current_nr_sectors) - uptodate = 1; + + if (rq->cmd == READ || rq->cmd == WRITE) + if (!rq->current_nr_sectors) + uptodate = 1; ide_end_request (uptodate, HWGROUP(drive)); } @@ -582,7 +597,7 @@ cdrom_saw_media_change (drive); /*printk("%s: media changed\n",drive->name);*/ return 0; - } else { + } else if (!pc->quiet) { /* Otherwise, print an error. */ ide_dump_status (drive, "packet command error", stat); @@ -661,11 +676,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; } @@ -678,7 +704,7 @@ 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) + ide_handler_t *handler, int cmd) { ide_startstop_t startstop; struct cdrom_info *info = drive->driver_data; @@ -687,8 +713,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); @@ -718,31 +751,32 @@ by cdrom_start_packet_command. HANDLER is the interrupt handler to call when the command completes or there's data ready. */ -static ide_startstop_t cdrom_transfer_packet_command (ide_drive_t *drive, +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) { + ide_startstop_t startstop; + if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) { /* Here we should have been called after receiving an interrupt from the device. DRQ should how be set. */ int stat_dum; - ide_startstop_t startstop; /* Check for errors. */ 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)) 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); + atapi_output_bytes(drive, cmd_buf, cmd_len); return ide_started; } @@ -834,8 +868,8 @@ drive->name, ireason); } - cdrom_end_request (0, drive); - return -1; + cdrom_end_request(0, drive); + return 1; } /* @@ -1076,7 +1110,7 @@ (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); @@ -1084,7 +1118,7 @@ /* Send the command to the drive and return. */ return cdrom_transfer_packet_command(drive, pc.c, sizeof(pc.c), - &cdrom_read_intr); + &cdrom_read_intr, WAIT_CMD); } @@ -1127,7 +1161,8 @@ 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) @@ -1136,11 +1171,13 @@ 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 - start it over entirely, or even put it back on the request queue. */ +/* + * Fix up a possibly partially-processed request so that we can + * start it over entirely + */ static void restore_request (struct request *rq) { if (rq->buffer != rq->bh->b_data) { @@ -1188,7 +1225,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); } /**************************************************************************** @@ -1302,9 +1339,12 @@ struct request *rq = HWGROUP(drive)->rq; struct packet_command *pc = (struct packet_command *)rq->buffer; + if (!pc->timeout) + pc->timeout = WAIT_CMD; + /* 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, pc->timeout); } @@ -1320,7 +1360,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); } @@ -1329,7 +1369,7 @@ static void cdrom_sleep (int time) { - current->state = TASK_INTERRUPTIBLE; + __set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(time); } @@ -1381,16 +1421,175 @@ return pc->stat ? -EIO : 0; } +/* + * Write handling + */ +static inline 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); + } + + 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)); + } + 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); + 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) { + /* 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; + } + + /* 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; + unsigned 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 devices I have + * support the streaming feature anyway, so who cares. + */ + pc.c[0] = GPCMD_WRITE_10; +#if 0 + pc.c[1] = 1 << 3; /* FUA bit */ +#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; switch (rq->cmd) { + case WRITE: + if (CDROM_CONFIG_FLAGS(drive)->dvd_ram) + cdrom_end_request(1, drive); case READ: { if (CDROM_CONFIG_FLAGS(drive)->seeking) { unsigned long elpased = jiffies - info->start_seek; @@ -1407,8 +1606,12 @@ } if (IDE_LARGE_SEEK(info->last_block, block, IDECD_SEEK_THRESHOLD) && drive->dsc_overlap) action = cdrom_start_seek (drive, block); - else - action = cdrom_start_read (drive, block); + else { + if (rq->cmd == READ) + action = cdrom_start_read(drive, block); + else + action = cdrom_start_write(drive); + } info->last_block = block; return action; } @@ -1422,9 +1625,8 @@ cdrom_end_request(1, drive); return ide_do_reset(drive); } - default: { - printk("ide-cd: bad cmd %d\n", rq -> cmd); + printk("ide-cd: bad cmd %d\n", rq->cmd); cdrom_end_request(0, drive); return ide_stopped; } @@ -1771,6 +1973,9 @@ HWIF(drive)->gd->sizes[drive->select.b.unit << PARTN_BITS] = (toc->capacity * SECTORS_PER_FRAME) >> (BLOCK_SIZE_BITS - 9); drive->part[0].nr_sects = toc->capacity * SECTORS_PER_FRAME; + HWIF(drive)->gd->sizes[drive->select.b.unit << PARTN_BITS] = (toc->capacity * SECTORS_PER_FRAME) >> (BLOCK_SIZE_BITS - 9); + drive->part[0].nr_sects = toc->capacity * SECTORS_PER_FRAME; + /* Remember that we've read this stuff. */ CDROM_STATE_FLAGS (drive)->toc_valid = 1; @@ -1816,8 +2021,9 @@ pc.c[2] = (speed >> 8) & 0xff; /* Read Drive speed in kbytes/second LSB */ pc.c[3] = speed & 0xff; - if ( CDROM_CONFIG_FLAGS(drive)->cd_r || - CDROM_CONFIG_FLAGS(drive)->cd_rw ) { + if (CDROM_CONFIG_FLAGS(drive)->cd_r || + CDROM_CONFIG_FLAGS(drive)->cd_rw || + CDROM_CONFIG_FLAGS(drive)->dvd_r) { /* Write Drive speed in kbytes/second MSB */ pc.c[4] = (speed >> 8) & 0xff; /* Write Drive speed in kbytes/second LSB */ @@ -1863,10 +2069,6 @@ return 0; } - - - - /* the generic packet interface to cdrom.c */ static int ide_cdrom_packet(struct cdrom_device_info *cdi, struct cdrom_generic_command *cgc) @@ -1874,21 +2076,20 @@ struct packet_command pc; ide_drive_t *drive = (ide_drive_t*) cdi->handle; + if (cgc->timeout <= 0) + cgc->timeout = WAIT_CMD; + /* here we queue the commands from the uniform CD-ROM layer. the packet must be complete, as we do not touch it at all. */ memset(&pc, 0, sizeof(pc)); - memcpy(pc.c, cgc->cmd, CDROM_PACKET_SIZE); + memcpy(pc.c, cgc->cmd, CDROM_CDB_SIZE); pc.buffer = cgc->buffer; pc.buflen = cgc->buflen; - cgc->stat = cdrom_queue_packet_command(drive, &pc); - - /* - * FIXME: copy sense, don't just assign pointer!! - */ - cgc->sense = pc.sense; - - return cgc->stat; + pc.quiet = cgc->quiet; + pc.timeout = cgc->timeout; + pc.sense = cgc->sense; + return cgc->stat = cdrom_queue_packet_command(drive, &pc); } static @@ -2179,6 +2380,12 @@ static void ide_cdrom_release_real (struct cdrom_device_info *cdi) { + struct cdrom_generic_command cgc; + + init_cdrom_command(&cgc, NULL, 0); + cgc.cmd[0] = GPCMD_FLUSH_CACHE; + cgc.quiet = 1; + (void) ide_cdrom_packet(cdi, &cgc); } @@ -2311,9 +2518,9 @@ if (cap.dvd_ram_read || cap.dvd_r_read || cap.dvd_rom) CDROM_CONFIG_FLAGS (drive)->dvd = 1; if (cap.dvd_ram_write) - CDROM_CONFIG_FLAGS (drive)->dvd_r = 1; - if (cap.dvd_r_write) CDROM_CONFIG_FLAGS (drive)->dvd_ram = 1; + if (cap.dvd_r_write) + CDROM_CONFIG_FLAGS (drive)->dvd_r = 1; if (cap.audio_play) CDROM_CONFIG_FLAGS (drive)->audio_play = 1; if (cap.mechtype == mechtype_caddy || cap.mechtype == mechtype_popup) @@ -2355,15 +2562,11 @@ printk(" %dX", CDROM_CONFIG_FLAGS(drive)->max_speed); printk(" %s", CDROM_CONFIG_FLAGS(drive)->dvd ? "DVD-ROM" : "CD-ROM"); - if (CDROM_CONFIG_FLAGS (drive)->dvd_r|CDROM_CONFIG_FLAGS (drive)->dvd_ram) - printk (" DVD%s%s", - (CDROM_CONFIG_FLAGS (drive)->dvd_r)? "-R" : "", - (CDROM_CONFIG_FLAGS (drive)->dvd_ram)? "AM" : ""); - - if (CDROM_CONFIG_FLAGS (drive)->cd_r|CDROM_CONFIG_FLAGS (drive)->cd_rw) - printk (" CD%s%s", - (CDROM_CONFIG_FLAGS (drive)->cd_r)? "-R" : "", - (CDROM_CONFIG_FLAGS (drive)->cd_rw)? "/RW" : ""); + if (CDROM_CONFIG_FLAGS(drive)->dvd_r || CDROM_CONFIG_FLAGS(drive)->dvd_ram) + printk (" DVD-R%s", (CDROM_CONFIG_FLAGS (drive)->dvd_ram)? "AM" : ""); + + if (CDROM_CONFIG_FLAGS(drive)->cd_r ||CDROM_CONFIG_FLAGS(drive)->cd_rw) + printk (" CD-R%s", (CDROM_CONFIG_FLAGS (drive)->cd_rw)? "/RW" : ""); if (CDROM_CONFIG_FLAGS (drive)->is_changer) printk (" changer w/%d slots", nslots); @@ -2380,7 +2583,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); @@ -2392,9 +2595,10 @@ struct cdrom_info *info = drive->driver_data; struct cdrom_device_info *cdi = &info->devinfo; int minor = drive->select.b.unit << PARTN_BITS; - int nslots; + int nslots, ro; - set_device_ro(MKDEV(HWIF(drive)->major, minor), 1); + ro = !CDROM_CONFIG_FLAGS(drive)->dvd_ram; + set_device_ro(MKDEV(HWIF(drive)->major, minor), ro); set_blocksize(MKDEV(HWIF(drive)->major, minor), CD_FRAMESIZE); drive->special.all = 0; @@ -2580,7 +2784,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); @@ -2588,7 +2792,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; @@ -2675,7 +2879,7 @@ kfree (info); continue; } - memset (info, 0, sizeof (struct cdrom_info)); + memset(info, 0, sizeof (struct cdrom_info)); drive->driver_data = info; DRIVER(drive)->busy++; if (ide_cdrom_setup (drive)) { diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.2.18-pre17/drivers/block/ide-cd.h linux/drivers/block/ide-cd.h --- /opt/kernel/linux-2.2.18-pre17/drivers/block/ide-cd.h Mon Sep 4 10:39:16 2000 +++ linux/drivers/block/ide-cd.h Tue Oct 24 15:29:43 2000 @@ -104,6 +104,7 @@ int buflen; int stat; int quiet; + int timeout; struct request_sense *sense; unsigned char c[12]; }; @@ -626,7 +627,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 +679,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 -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.2.18-pre17/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c --- /opt/kernel/linux-2.2.18-pre17/drivers/cdrom/cdrom.c Tue Oct 24 14:42:59 2000 +++ linux/drivers/cdrom/cdrom.c Tue Oct 24 15:35:37 2000 @@ -222,11 +222,19 @@ 3.11 Jun 12, 2000 - Jens Axboe -- Fix bug in getting rpc phase 2 region info. -- Reinstate "correct" CDROMPLAYTRKIND - + + 3.12 Oct 22, 2000 - Jens Axboe + -- Use quiet bit on packet commands not known to work + -- Add cgc command timeout + -- Fixup CDROMREADXXX, allow multiple frames per sys call + -- Cleanup + misc fixes to CDROM_SEND_PACKET + -- Fixup bugs in CDROMREAD where we may end up copying to much at + the end + -------------------------------------------------------------------------*/ -#define REVISION "Revision: 3.11" -#define VERSION "Id: cdrom.c 3.11 2000/06/12" +#define REVISION "Revision: 3.12" +#define VERSION "Id: cdrom.c 3.12 2000/10/22" /* 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: */ @@ -943,6 +951,7 @@ memset(buf, 0, len); cgc->buffer = (char *) buf; cgc->buflen = len; + cgc->timeout = 5*HZ; } /* DVD handling */ @@ -1345,16 +1354,32 @@ return cdo->generic_packet(cdi, cgc); } -static int cdrom_mode_select_6(struct cdrom_device_info *cdi, - struct cdrom_generic_command *cgc) +/* + * Required when we need to use READ_10 to issue other than 2048 block + * reads + */ +static int cdrom_switch_blocksize(struct cdrom_device_info *cdi, int size) { struct cdrom_device_ops *cdo = cdi->ops; + struct cdrom_generic_command cgc; + struct modesel_head mh; - memset(cgc->cmd, 0, sizeof(cgc->cmd)); - cgc->cmd[0] = GPCMD_MODE_SELECT_6; - cgc->cmd[1] = 0x10; - cgc->cmd[4] = cgc->buflen & 0xff; - return cdo->generic_packet(cdi, cgc); + memset(&mh, 0, sizeof(mh)); + mh.block_desc_length = 0x08; + mh.block_length_med = (size >> 8) & 0xff; + mh.block_length_lo = size & 0xff; + + memset(&cgc, 0, sizeof(cgc)); + cgc.cmd[0] = 0x15; + cgc.cmd[1] = 1 << 4; + cgc.cmd[4] = 12; + cgc.buflen = sizeof(mh); + cgc.buffer = (char *) &mh; + mh.block_desc_length = 0x08; + mh.block_length_med = (size >> 8) & 0xff; + mh.block_length_lo = size & 0xff; + + return cdo->generic_packet(cdi, &cgc); } static int cdrom_read_subchannel(struct cdrom_device_info *cdi, @@ -1414,7 +1439,7 @@ } /* very generic interface for reading the various types of blocks */ -static int cdrom_read_block(struct cdrom_device_info *cdi, +static int __cdrom_read_block(struct cdrom_device_info *cdi, struct cdrom_generic_command *cgc, int lba, int nblocks, int format, int blksize) { @@ -1434,6 +1459,7 @@ cgc->cmd[7] = (nblocks >> 8) & 0xff; cgc->cmd[8] = nblocks & 0xff; cgc->buflen = blksize * nblocks; + cgc->data_direction = CGC_DATA_READ; /* set the header info returned */ switch (blksize) { @@ -1446,6 +1472,28 @@ return cdo->generic_packet(cdi, cgc); } +static int cdrom_read_block(struct cdrom_device_info *cdi, + struct cdrom_generic_command *cgc, + int lba, int nblocks, int format, int blksize, + int ssize) +{ + int ret; + + cgc->data_direction = CGC_DATA_READ; + ret = __cdrom_read_block(cdi, cgc, lba, nblocks, format, blksize); + if (ret && ssize) { + /* + * SCSI-II devices are not required to support + * READ_CD, so let's try switching block size + */ + if (cdrom_switch_blocksize(cdi, blksize)) + return ret; + ret = cdrom_read_cd(cdi, cgc, lba, blksize, nblocks); + (void) cdrom_switch_blocksize(cdi, CD_FRAMESIZE); + } + return ret; +} + /* Just about every imaginable ioctl is supported in the Uniform layer * these days. ATAPI / SCSI specific code now mainly resides in * mmc_ioct(). @@ -1829,23 +1877,61 @@ return (((m * CD_SECS) + s) * CD_FRAMES + f) - CD_MSF_OFFSET; } -/* - * Required when we need to use READ_10 to issue other than 2048 block - * reads - */ -static int cdrom_switch_blocksize(struct cdrom_device_info *cdi, int size) +static int cdrom_do_send_packet(struct cdrom_device_info *cdi, + struct cdrom_generic_command *cgc) { - struct cdrom_generic_command cgc; - struct modesel_head mh; + struct request_sense *usense, sense; + unsigned char *ubuf = NULL; + int ret; - memset(&mh, 0, sizeof(mh)); - memset(&cgc, 0, sizeof(cgc)); - mh.block_desc_length = 0x08; - mh.block_length_med = (size >> 8) & 0xff; - mh.block_length_lo = size & 0xff; - cgc.buflen = sizeof(mh); - cgc.buffer = (char *) &mh; - return cdrom_mode_select_6(cdi, &cgc); + if (cgc->buflen < 0 || cgc->buflen >= 131072) + return -EINVAL; + + /* + * setup sense and data buffers, check access perms, etc + */ + usense = cgc->sense; + cgc->sense = &sense; + if (!access_ok(VERIFY_WRITE, usense, sizeof(*usense))) + return -EFAULT; + + switch (cgc->data_direction) { + case CGC_DATA_READ: + ubuf = cgc->buffer; + if (!access_ok(VERIFY_READ, ubuf, cgc->buflen)) + return -EFAULT; + cgc->buffer = kmalloc(cgc->buflen, GFP_KERNEL); + if (cgc->buffer == NULL) + return -ENOMEM; + break; + case CGC_DATA_WRITE: + ubuf = cgc->buffer; + if (!access_ok(VERIFY_WRITE, ubuf, cgc->buflen)) + return -EFAULT; + cgc->buffer = kmalloc(cgc->buflen, GFP_KERNEL); + if (cgc->buffer == NULL) + return -ENOMEM; + __copy_from_user(cgc->buffer, ubuf, cgc->buflen); + break; + case CGC_DATA_NONE: + break; + case CGC_DATA_UNKNOWN: + default: + return -EINVAL; + } + + /* + * fire off the command + */ + ret = cdi->ops->generic_packet(cdi, cgc); + + __copy_to_user(usense, cgc->sense, sizeof(*usense)); + + if (!ret && cgc->data_direction == CGC_DATA_READ) + __copy_to_user(ubuf, cgc->buffer, cgc->buflen); + if (cgc->data_direction != CGC_DATA_NONE) + kfree(cgc->buffer); + return ret; } static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, @@ -1866,8 +1952,10 @@ case CDROMREADMODE1: case CDROMREADMODE2: { struct cdrom_msf msf; - int blocksize = 0, format = 0, lba; + int blocksize = 0, format = 0, frames, nframes; + int long lba, end; + cdinfo(CD_DO_IOCTL, "entering CDROMREADXXX\n"); switch (cmd) { case CDROMREADRAW: blocksize = CD_FRAMESIZE_RAW; @@ -1882,35 +1970,48 @@ } IOCTL_IN(arg, struct cdrom_msf, msf); lba = msf_to_lba(msf.cdmsf_min0,msf.cdmsf_sec0,msf.cdmsf_frame0); - /* FIXME: we need upper bound checking, too!! */ - if (lba < 0) + end = msf_to_lba(msf.cdmsf_min1,msf.cdmsf_sec1,msf.cdmsf_frame1); + + /* + * compatability with programs not setting end boundary + */ + if (end == -CD_MSF_OFFSET) + end = lba + 1; + + if (lba < 0 || end <= 0 || (int)(end - lba) <= 0) return -EINVAL; - cgc.buffer = (char *) kmalloc(blocksize, GFP_KERNEL); + + nframes = frames = end - lba; + if (frames > 8) + frames = 8; + + cgc.buffer = (char *) kmalloc(frames * blocksize, GFP_KERNEL); if (cgc.buffer == NULL) return -ENOMEM; - ret = cdrom_read_block(cdi, &cgc, lba, 1, format, blocksize); - if (ret) { - /* - * SCSI-II devices are not required to support - * READ_CD, so let's try switching block size - */ - /* FIXME: switch back again... */ - if ((ret = cdrom_switch_blocksize(cdi, blocksize))) { - kfree(cgc.buffer); - return ret; - } - ret = cdrom_read_cd(cdi, &cgc, lba, blocksize, 1); - ret |= cdrom_switch_blocksize(cdi, blocksize); + + if (!access_ok(VERIFY_WRITE, arg, nframes * blocksize)) { + kfree(cgc.buffer); + return -EFAULT; + } + while (nframes > 0) { + if (frames > nframes) + frames = nframes; + ret = cdrom_read_block(cdi, &cgc, lba, frames, format, blocksize, 1); + if (ret) + break; + __copy_to_user((char *)arg, cgc.buffer, frames * blocksize); + arg += (frames + blocksize); + nframes -= frames; + lba += frames; } - if (!ret && copy_to_user((char *)arg, cgc.buffer, blocksize)) - ret = -EFAULT; kfree(cgc.buffer); return ret; } case CDROMREADAUDIO: { struct cdrom_read_audio ra; - int lba, frames; + int frames, size, lba; + cdinfo(CD_DO_IOCTL, "entering CDROMREADAUDIO\n"); IOCTL_IN(arg, struct cdrom_read_audio, ra); if (ra.addr_format == CDROM_MSF) @@ -1928,21 +2029,21 @@ /* do max 8 frames at the time */ frames = ra.nframes > 8 ? 8 : ra.nframes; + size = frames * CD_FRAMESIZE_RAW; - if ((cgc.buffer = (char *) kmalloc(CD_FRAMESIZE_RAW * frames, - GFP_KERNEL)) == NULL) + if ((cgc.buffer = (char *) kmalloc(size, GFP_KERNEL)) == NULL) return -ENOMEM; if (!access_ok(VERIFY_WRITE, ra.buf, ra.nframes*CD_FRAMESIZE_RAW)) { kfree(cgc.buffer); return -EFAULT; } - while (ra.nframes > 0) { - ret = cdrom_read_block(cdi, &cgc, lba, frames, 1, CD_FRAMESIZE_RAW); + if (frames > ra.nframes) + frames = ra.nframes; + ret = cdrom_read_block(cdi, &cgc, lba, frames, 1, CD_FRAMESIZE_RAW, 0); if (ret) break; - __copy_to_user(ra.buf, cgc.buffer, - CD_FRAMESIZE_RAW * frames); + __copy_to_user(ra.buf, cgc.buffer, size); ra.buf += (CD_FRAMESIZE_RAW * frames); ra.nframes -= frames; lba += frames; @@ -2049,7 +2150,6 @@ cgc.buffer = buffer; return cdrom_mode_select(cdi, &cgc); } - case CDROMSTART: case CDROMSTOP: { cdinfo(CD_DO_IOCTL, "entering CDROMSTART/CDROMSTOP\n"); @@ -2058,7 +2158,6 @@ cgc.cmd[4] = (cmd == CDROMSTART) ? 1 : 0; return cdo->generic_packet(cdi, &cgc); } - case CDROMPAUSE: case CDROMRESUME: { cdinfo(CD_DO_IOCTL, "entering CDROMPAUSE/CDROMRESUME\n"); @@ -2066,7 +2165,6 @@ cgc.cmd[8] = (cmd == CDROMRESUME) ? 1 : 0; return cdo->generic_packet(cdi, &cgc); } - case DVD_READ_STRUCT: { dvd_struct *s; int size = sizeof(dvd_struct); @@ -2088,7 +2186,6 @@ kfree(s); return ret; } - case DVD_AUTH: { dvd_authinfo ai; if (!CDROM_CAN(CDC_DVD)) @@ -2100,54 +2197,12 @@ IOCTL_OUT(arg, dvd_authinfo, ai); return 0; } - case CDROM_SEND_PACKET: { - __u8 *userbuf, copy = 0; - struct request_sense *sense; if (!CDROM_CAN(CDC_GENERIC_PACKET)) return -ENOSYS; cdinfo(CD_DO_IOCTL, "entering CDROM_SEND_PACKET\n"); IOCTL_IN(arg, struct cdrom_generic_command, cgc); - copy = !!cgc.buflen; - userbuf = cgc.buffer; - cgc.buffer = NULL; - sense = cgc.sense; - if (userbuf != NULL && copy) { - /* usually commands just copy data one way, i.e. - * we send a buffer to the drive and the command - * specifies whether the drive will read or - * write to that buffer. usually the buffers - * are very small, so we don't loose that much - * by doing a redundant copy each time. */ - if (!access_ok(VERIFY_WRITE, userbuf, cgc.buflen)) { - printk("can't get write perms\n"); - return -EFAULT; - } - if (!access_ok(VERIFY_READ, userbuf, cgc.buflen)) { - printk("can't get read perms\n"); - return -EFAULT; - } - } - /* reasonable limits */ - if (cgc.buflen < 0 || cgc.buflen > 131072) { - printk("invalid size given\n"); - return -EINVAL; - } - if (copy) { - cgc.buffer = kmalloc(cgc.buflen, GFP_KERNEL); - if (cgc.buffer == NULL) - return -ENOMEM; - __copy_from_user(cgc.buffer, userbuf, cgc.buflen); - } - ret = cdo->generic_packet(cdi, &cgc); - if (copy && !ret) - __copy_to_user(userbuf, cgc.buffer, cgc.buflen); - /* copy back sense data */ - if (sense != NULL) - if (copy_to_user(sense, cgc.sense, sizeof(struct request_sense))) - ret = -EFAULT; - kfree(cgc.buffer); - return ret; + return cdrom_do_send_packet(cdi, &cgc); } case CDROM_NEXT_WRITABLE: { long next = 0; @@ -2184,6 +2239,7 @@ cgc.cmd[4] = (track & 0xff00) >> 8; cgc.cmd[5] = track & 0xff; cgc.cmd[8] = 8; + cgc.quiet = 1; if ((ret = cdo->generic_packet(cdi, &cgc))) return ret; @@ -2204,6 +2260,7 @@ init_cdrom_command(&cgc, di, sizeof(*di)); cgc.cmd[0] = GPCMD_READ_DISC_INFO; cgc.cmd[8] = cgc.buflen = 2; + cgc.quiet = 1; if ((ret = cdo->generic_packet(cdi, &cgc))) return ret; @@ -2235,9 +2292,6 @@ int ret = -1; if (!CDROM_CAN(CDC_GENERIC_PACKET)) - goto use_toc; - - if (!CDROM_CAN(CDC_CD_R | CDC_CD_RW)) goto use_toc; if ((ret = cdrom_get_disc_info(dev, &di))) diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.2.18-pre17/drivers/scsi/sr.c linux/drivers/scsi/sr.c --- /opt/kernel/linux-2.2.18-pre17/drivers/scsi/sr.c Tue Oct 24 14:43:45 2000 +++ linux/drivers/scsi/sr.c Tue Oct 24 15:34:38 2000 @@ -1068,18 +1068,22 @@ /* scsi_do_cmd sets the command length */ SCpnt->cmd_len = 0; + if (cgc->timeout <= 0) + cgc->timeout = 5 * HZ; + { struct semaphore sem = MUTEX_LOCKED; SCpnt->request.sem = &sem; spin_lock_irqsave(&io_request_lock, flags); scsi_do_cmd(SCpnt, (void *)cgc->cmd, (void *) buffer, - cgc->buflen, sr_init_done, SR_TIMEOUT, + cgc->buflen, sr_init_done, cgc->timeout, MAX_RETRIES); spin_unlock_irqrestore(&io_request_lock, flags); down(&sem); } - stat = SCpnt->result; + cgc->stat = stat = SCpnt->result; + memcpy(cgc->sense, SCpnt->sense_buffer, sizeof(SCpnt->sense_buffer)); /* release */ SCpnt->request.rq_dev = MKDEV(0, 0); diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.2.18-pre17/include/linux/cdrom.h linux/include/linux/cdrom.h --- /opt/kernel/linux-2.2.18-pre17/include/linux/cdrom.h Mon Sep 4 10:39:28 2000 +++ linux/include/linux/cdrom.h Tue Oct 24 15:25:12 2000 @@ -264,29 +264,13 @@ unsigned short len; }; -#define CDROM_PACKET_SIZE 12 +#define CDROM_CDB_SIZE 12 -/* - * These are for 2.3/4 only, but lets have them in 2.2 as well so that - * apps don't need to check for versions. - */ #define CGC_DATA_UNKNOWN 0 #define CGC_DATA_WRITE 1 #define CGC_DATA_READ 2 #define CGC_DATA_NONE 3 -/* for CDROM_PACKET_COMMAND ioctl */ -struct cdrom_generic_command -{ - unsigned char cmd[CDROM_PACKET_SIZE]; - unsigned char *buffer; - unsigned int buflen; - int stat; - struct request_sense *sense; - unsigned char data_direction; - void *reserved[3]; -}; - /* * A CD-ROM physical sector size is 2048, 2052, 2056, 2324, 2332, 2336, @@ -493,6 +477,7 @@ /* Mode page codes for mode sense/set */ #define GPMODE_R_W_ERROR_PAGE 0x01 #define GPMODE_WRITE_PARMS_PAGE 0x05 +#define GPMODE_WCACHING_PAGE 0x08 #define GPMODE_AUDIO_CTL_PAGE 0x0e #define GPMODE_POWER_PAGE 0x1a #define GPMODE_FAULT_FAIL_PAGE 0x1c @@ -503,7 +488,10 @@ * of MODE_SENSE_POWER_PAGE */ #define GPMODE_CDROM_PAGE 0x0d - +#define GPMODE_PAGE_CURRENT 0 +#define GPMODE_PAGE_CHANGE 1 +#define GPMODE_PAGE_DEFAULT 2 +#define GPMODE_PAGE_SAVE 3 /* DVD struct types */ #define DVD_STRUCT_PHYSICAL 0x00 @@ -681,7 +669,8 @@ struct dvd_lu_send_rpcstate lrpcs; } dvd_authinfo; -struct request_sense { +struct request_sense +{ #if defined(__BIG_ENDIAN_BITFIELD) __u8 valid : 1; __u8 error_code : 7; @@ -709,6 +698,20 @@ __u8 fruc; __u8 sks[3]; __u8 asb[46]; +}; + +/* for CDROM_PACKET_COMMAND ioctl */ +struct cdrom_generic_command +{ + unsigned char cmd[CDROM_CDB_SIZE]; + unsigned char *buffer; + unsigned int buflen; + int stat; + struct request_sense *sense; + unsigned char data_direction; + int quiet; + int timeout; + void *reserved[1]; }; #ifdef __KERNEL__ diff -ur --exclude-from /home/axboe/exclude /opt/kernel/linux-2.2.18-pre17/include/scsi/scsi.h linux/include/scsi/scsi.h --- /opt/kernel/linux-2.2.18-pre17/include/scsi/scsi.h Tue Oct 24 14:44:48 2000 +++ linux/include/scsi/scsi.h Tue Oct 24 15:13:31 2000 @@ -70,6 +70,9 @@ #define CHANGE_DEFINITION 0x40 #define WRITE_SAME 0x41 #define READ_TOC 0x43 +#define PLAY_AUDIO_10 0x45 +#define PLAY_AUDIO_MSF 0x47 +#define PLAY_AUDIO_TI 0x48 #define LOG_SELECT 0x4c #define LOG_SENSE 0x4d #define MODE_SELECT_10 0x55