--- /dev/null
+diff -ur -X /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.19-pre4/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c
+--- /opt/kernel/linux-2.4.19-pre4/drivers/cdrom/cdrom.c Fri Nov 16 19:14:08 2001
++++ linux/drivers/cdrom/cdrom.c Tue Mar 26 09:49:44 2002
+@@ -228,10 +228,16 @@
+ 3.12 Oct 18, 2000 - Jens Axboe <axboe@suse.de>
+ -- Use quiet bit on packet commands not known to work
+
++ 3.20 Sep 24, 2001 - Jens Axboe <axboe@suse.de>
++ -- Various fixes and lots of cleanups not listed :-)
++ -- Locking fixes
++ -- Mt Rainier support
++ -- DVD-RAM write open fixes
++
+ -------------------------------------------------------------------------*/
+
+-#define REVISION "Revision: 3.12"
+-#define VERSION "Id: cdrom.c 3.12 2000/10/18"
++#define REVISION "Revision: 3.20"
++#define VERSION "Id: cdrom.c 3.20 2001/09/24"
+
+ /* 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: */
+@@ -266,7 +272,6 @@
+ #include <linux/init.h>
+
+ #include <asm/fcntl.h>
+-#include <asm/segment.h>
+ #include <asm/uaccess.h>
+
+ /* used to tell the module to turn on full debugging messages */
+@@ -279,11 +284,25 @@
+ static int lockdoor = 1;
+ /* will we ever get to use this... sigh. */
+ static int check_media_type;
++/* automatically restart mrw format */
++static int mrw_format_restart = 1;
+ MODULE_PARM(debug, "i");
+ MODULE_PARM(autoclose, "i");
+ MODULE_PARM(autoeject, "i");
+ MODULE_PARM(lockdoor, "i");
+ MODULE_PARM(check_media_type, "i");
++MODULE_PARM(mrw_format_restart, "i");
++
++static spinlock_t cdrom_lock = SPIN_LOCK_UNLOCKED;
++
++static const char *mrw_format_status[] = {
++ "not mrw",
++ "bgformat inactive",
++ "bgformat active",
++ "mrw complete",
++};
++
++static const char *mrw_address_space[] = { "DMA", "GAA" };
+
+ #if (ERRLOGMASK!=CD_NOTHING)
+ #define cdinfo(type, fmt, args...) \
+@@ -321,6 +340,10 @@
+ int cdrom_get_last_written(kdev_t dev, long *last_written);
+ int cdrom_get_next_writable(kdev_t dev, long *next_writable);
+
++static int __cdrom_get_di(struct cdrom_device_info *cdi, disc_information *di);
++
++static int cdrom_mrw_exit(struct cdrom_device_info *cdi);
++
+ #ifdef CONFIG_SYSCTL
+ static void cdrom_sysctl_register(void);
+ #endif /* CONFIG_SYSCTL */
+@@ -348,13 +371,14 @@
+ return -1;
+ if (cdo->open == NULL || cdo->release == NULL)
+ return -2;
+- if ( !banner_printed ) {
++ if (!banner_printed) {
+ printk(KERN_INFO "Uniform CD-ROM driver " REVISION "\n");
+ banner_printed = 1;
+ #ifdef CONFIG_SYSCTL
+ cdrom_sysctl_register();
+ #endif /* CONFIG_SYSCTL */
+ }
++
+ ENSURE(drive_status, CDC_DRIVE_STATUS );
+ ENSURE(media_changed, CDC_MEDIA_CHANGED);
+ ENSURE(tray_move, CDC_CLOSE_TRAY | CDC_OPEN_TRAY);
+@@ -379,6 +403,9 @@
+ if (check_media_type==1)
+ cdi->options |= (int) CDO_CHECK_TYPE;
+
++ if (CDROM_CAN(CDC_MRW_W))
++ cdi->exit = cdrom_mrw_exit;
++
+ if (!devfs_handle)
+ devfs_handle = devfs_mk_dir (NULL, "cdroms", NULL);
+ cdi->number = devfs_alloc_unique_number (&cdrom_numspace);
+@@ -399,9 +426,12 @@
+ devfs_auto_unregister (cdi->de, slave);
+ }
+ }
++
+ cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name);
++ spin_lock(&cdrom_lock);
+ cdi->next = topCdromPtr;
+ topCdromPtr = cdi;
++ spin_unlock(&cdrom_lock);
+ return 0;
+ }
+ #undef ENSURE
+@@ -417,18 +447,26 @@
+ return -1;
+
+ prev = NULL;
++ spin_lock(&cdrom_lock);
+ cdi = topCdromPtr;
+ while (cdi != NULL && cdi->dev != unreg->dev) {
+ prev = cdi;
+ cdi = cdi->next;
+ }
+
+- if (cdi == NULL)
++ if (cdi == NULL) {
++ spin_unlock(&cdrom_lock);
+ return -2;
++ }
+ if (prev)
+ prev->next = cdi->next;
+ else
+ topCdromPtr = cdi->next;
++ spin_unlock(&cdrom_lock);
++
++ if (cdi->exit)
++ cdi->exit(cdi);
++
+ cdi->ops->n_minors--;
+ devfs_unregister (cdi->de);
+ devfs_dealloc_unique_number (&cdrom_numspace, cdi->number);
+@@ -440,13 +478,292 @@
+ {
+ struct cdrom_device_info *cdi;
+
++ spin_lock(&cdrom_lock);
+ cdi = topCdromPtr;
+ while (cdi != NULL && cdi->dev != dev)
+ cdi = cdi->next;
++ spin_unlock(&cdrom_lock);
+
+ return cdi;
+ }
+
++int cdrom_get_media_event(struct cdrom_device_info *cdi,
++ struct media_event_desc *med)
++{
++ struct cdrom_generic_command cgc;
++ unsigned char buffer[8];
++ struct event_header *eh = (struct event_header *) buffer;
++
++ init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);
++ cgc.cmd[0] = GPCMD_GET_EVENT_STATUS_NOTIFICATION;
++ cgc.cmd[1] = 1; /* IMMED */
++ cgc.cmd[4] = 1 << 4; /* media event */
++ cgc.cmd[8] = sizeof(buffer);
++ cgc.quiet = 1;
++
++ if (cdi->ops->generic_packet(cdi, &cgc))
++ return 1;
++
++ if (be16_to_cpu(eh->data_len) < sizeof(*med))
++ return 1;
++
++ memcpy(med, &buffer[sizeof(*eh)], sizeof(*med));
++ return 0;
++}
++
++/*
++ * the first prototypes used 0x2c as the page code for the mrw mode page,
++ * subsequently this was changed to 0x03. probe the one used by this drive
++ */
++int cdrom_mrw_probe_pc(struct cdrom_device_info *cdi)
++{
++ struct cdrom_generic_command cgc;
++ char buffer[16];
++
++ init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);
++
++ cgc.buffer = buffer;
++ cgc.buflen = sizeof(buffer);
++ cgc.timeout = HZ;
++ cgc.quiet = 1;
++
++ if (!cdrom_mode_sense(cdi, &cgc, MRW_MODE_PC, 0)) {
++ cdi->mrw_mode_page = MRW_MODE_PC;
++ return 0;
++ } else if (!cdrom_mode_sense(cdi, &cgc, MRW_MODE_PC_PRE1, 0)) {
++ cdi->mrw_mode_page = MRW_MODE_PC_PRE1;
++ return 0;
++ } else {
++ printk("cdrom: %s: unknown mrw mode page\n", cdi->name);
++ return 1;
++ }
++
++ printk("cdrom: %s: mrw mode page %x\n", cdi->name, cdi->mrw_mode_page);
++}
++
++int cdrom_is_mrw(struct cdrom_device_info *cdi, int *write)
++{
++ struct cdrom_generic_command cgc;
++ struct mrw_feature_desc *mfd;
++ unsigned char buffer[16];
++ int ret;
++
++ init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);
++
++ cgc.cmd[0] = GPCMD_GET_CONFIGURATION;
++ cgc.cmd[3] = CDF_MRW;
++ cgc.cmd[8] = sizeof(buffer);
++ cgc.quiet = 1;
++
++ if ((ret = cdi->ops->generic_packet(cdi, &cgc)))
++ return ret;
++
++ mfd = (struct mrw_feature_desc *)&buffer[sizeof(struct feature_header)];
++ *write = mfd->write;
++
++ if ((ret = cdrom_mrw_probe_pc(cdi)))
++ return ret;
++
++ return 0;
++}
++
++static int cdrom_mrw_bgformat(struct cdrom_device_info *cdi, int cont)
++{
++ struct cdrom_generic_command cgc;
++ unsigned char buffer[12];
++ int ret;
++
++ printk("cdrom: %sstarting format\n", cont ? "Re" : "");
++
++ /*
++ * FmtData bit set (bit 4), format type is 1
++ */
++ init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_WRITE);
++ cgc.cmd[0] = GPCMD_FORMAT_UNIT;
++ cgc.cmd[1] = (1 << 4) | 1;
++
++ cgc.timeout = 5 * 60 * HZ;
++
++ /*
++ * 4 byte format list header, 8 byte format list descriptor
++ */
++ buffer[1] = 1 << 1;
++ buffer[3] = 8;
++
++ /*
++ * nr_blocks field
++ */
++ buffer[4] = 0xff;
++ buffer[5] = 0xff;
++ buffer[6] = 0xff;
++ buffer[7] = 0xff;
++
++ buffer[8] = 0x24 << 2;
++ buffer[11] = cont;
++
++ ret = cdi->ops->generic_packet(cdi, &cgc);
++ if (ret)
++ printk("cdrom: bgformat failed\n");
++
++ return ret;
++}
++
++static int cdrom_mrw_bgformat_susp(struct cdrom_device_info *cdi, int immed)
++{
++ struct cdrom_generic_command cgc;
++
++ init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);
++ cgc.cmd[0] = GPCMD_CLOSE_TRACK;
++
++ /*
++ * Session = 1, Track = 0
++ */
++ cgc.cmd[1] = !!immed;
++ cgc.cmd[2] = 1 << 1;
++
++ cgc.timeout = 300 * HZ;
++
++ return cdi->ops->generic_packet(cdi, &cgc);
++}
++
++static int cdrom_flush_cache(struct cdrom_device_info *cdi)
++{
++ struct cdrom_generic_command cgc;
++
++ init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);
++ cgc.cmd[0] = GPCMD_FLUSH_CACHE;
++
++ cgc.timeout = 5 * 60 * HZ;
++
++ return cdi->ops->generic_packet(cdi, &cgc);
++}
++
++static int cdrom_mrw_exit(struct cdrom_device_info *cdi)
++{
++ disc_information di;
++ int ret = 0;
++
++ if (__cdrom_get_di(cdi, &di))
++ return 1;
++
++ if (di.mrw_status == CDM_MRW_BGFORMAT_ACTIVE) {
++ printk("cdrom: issuing MRW back ground format suspend\n");
++ ret = cdrom_mrw_bgformat_susp(cdi, 0);
++ }
++
++ if (!ret)
++ ret = cdrom_flush_cache(cdi);
++
++ return ret;
++}
++
++static int cdrom_mrw_set_lba_space(struct cdrom_device_info *cdi, int space)
++{
++ struct cdrom_generic_command cgc;
++ struct mode_page_header *mph;
++ char buffer[16];
++ int ret, offset, size;
++
++ init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);
++
++ cgc.buffer = buffer;
++ cgc.buflen = sizeof(buffer);
++
++ if ((ret = cdrom_mode_sense(cdi, &cgc, cdi->mrw_mode_page, 0)))
++ return ret;
++
++ mph = (struct mode_page_header *) buffer;
++ offset = be16_to_cpu(mph->desc_length);
++ size = be16_to_cpu(mph->mode_data_length) + 2;
++
++ buffer[offset + 3] = space;
++ cgc.buflen = size;
++
++ if ((ret = cdrom_mode_select(cdi, &cgc)))
++ return ret;
++
++ printk("cdrom: %s: mrw address space %s selected\n", cdi->name, mrw_address_space[space]);
++ return 0;
++}
++
++static int cdrom_media_erasable(struct cdrom_device_info *cdi)
++{
++ disc_information di;
++
++ if (__cdrom_get_di(cdi, &di))
++ return 0;
++
++ return di.erasable;
++}
++
++/*
++ * FIXME: check RO bit
++ */
++static int cdrom_dvdram_open_write(struct cdrom_device_info *cdi)
++{
++ return !cdrom_media_erasable(cdi);
++}
++
++static int cdrom_mrw_open_write(struct cdrom_device_info *cdi)
++{
++ disc_information di;
++ int ret;
++
++ /*
++ * always reset to GAA lba space on open
++ */
++ if (cdrom_mrw_set_lba_space(cdi, MRW_LBA_GAA))
++ return 1;
++
++ if (__cdrom_get_di(cdi, &di))
++ return 1;
++
++ if (!di.erasable)
++ return 1;
++
++ /*
++ * mrw_status
++ * 0 - not MRW formatted
++ * 1 - MRW bgformat started, but not running or complete
++ * 2 - MRW bgformat in progress
++ * 3 - MRW formatting complete
++ */
++ ret = 0;
++ printk("cdrom open: mrw_status '%s'\n", mrw_format_status[di.mrw_status]);
++ if (!di.mrw_status)
++ ret = 1;
++ else if (di.mrw_status == CDM_MRW_BGFORMAT_INACTIVE && mrw_format_restart)
++ ret = cdrom_mrw_bgformat(cdi, 1);
++
++ return ret;
++}
++
++/*
++ * returns 0 for ok to open write, non-0 to disallow
++ */
++static int cdrom_open_write(struct cdrom_device_info *cdi)
++{
++ int ret;
++
++ if (CDROM_CAN(CDC_MRW_W))
++ ret = cdrom_mrw_open_write(cdi);
++ else if (CDROM_CAN(CDC_DVD_RAM))
++ ret = cdrom_dvdram_open_write(cdi);
++ else
++ ret = 1;
++
++ return ret;
++}
++
++static int cdrom_close_write(struct cdrom_device_info *cdi)
++{
++#if 0
++ return cdrom_flush_cache(cdi);
++#else
++ return 0;
++#endif
++}
++
+ /* We use the open-option O_NONBLOCK to indicate that the
+ * purpose of opening is only for subsequent ioctl() calls; no device
+ * integrity checks are performed.
+@@ -465,8 +782,15 @@
+ if ((cdi = cdrom_find_device(dev)) == NULL)
+ return -ENODEV;
+
+- if ((fp->f_mode & FMODE_WRITE) && !CDROM_CAN(CDC_DVD_RAM))
+- return -EROFS;
++ cdi->use_count++;
++ ret = -EROFS;
++ if (fp->f_mode & FMODE_WRITE) {
++ printk("cdrom: %s opening for WRITE\n", current->comm);
++ if (!CDROM_CAN(CDC_RAM))
++ goto out;
++ if (cdrom_open_write(cdi))
++ goto out;
++ }
+
+ /* if this was a O_NONBLOCK open and we should honor the flags,
+ * do a quick open without drive/disc integrity checks. */
+@@ -475,12 +799,13 @@
+ else
+ ret = open_for_data(cdi);
+
+- if (!ret) cdi->use_count++;
+-
+ cdinfo(CD_OPEN, "Use count for \"/dev/%s\" now %d\n", cdi->name, cdi->use_count);
+ /* Do this on open. Don't wait for mount, because they might
+ not be mounting, but opening with O_NONBLOCK */
+ check_disk_change(dev);
++out:
++ if (ret)
++ cdi->use_count--;
+ return ret;
+ }
+
+@@ -491,6 +816,7 @@
+ struct cdrom_device_ops *cdo = cdi->ops;
+ tracktype tracks;
+ cdinfo(CD_OPEN, "entering open_for_data\n");
++
+ /* Check if the driver can report drive status. If it can, we
+ can do clever things. If it can't, well, we at least tried! */
+ if (cdo->drive_status != NULL) {
+@@ -568,7 +894,7 @@
+ cdinfo(CD_OPEN, "open device failed.\n");
+ goto clean_up_and_return;
+ }
+- if (CDROM_CAN(CDC_LOCK) && cdi->options & CDO_LOCK) {
++ if (CDROM_CAN(CDC_LOCK) && (cdi->options & CDO_LOCK)) {
+ cdo->lock_door(cdi, 1);
+ cdinfo(CD_OPEN, "door locked.\n");
+ }
+@@ -646,7 +972,6 @@
+ return 0;
+ }
+
+-
+ /* Admittedly, the logic below could be performed in a nicer way. */
+ int cdrom_release(struct inode *ip, struct file *fp)
+ {
+@@ -657,17 +982,23 @@
+
+ cdinfo(CD_CLOSE, "entering cdrom_release\n");
+
+- if (cdi->use_count > 0)
+- cdi->use_count--;
+- if (cdi->use_count == 0)
++ if (!--cdi->use_count) {
+ cdinfo(CD_CLOSE, "Use count for \"/dev/%s\" now zero\n", cdi->name);
+- if (cdi->use_count == 0 &&
+- cdo->capability & CDC_LOCK && !keeplocked) {
+- cdinfo(CD_CLOSE, "Unlocking door!\n");
+- cdo->lock_door(cdi, 0);
++ if ((cdo->capability & CDC_LOCK) && !keeplocked) {
++ cdinfo(CD_CLOSE, "Unlocking door!\n");
++ cdo->lock_door(cdi, 0);
++ }
+ }
++
+ opened_for_data = !(cdi->options & CDO_USE_FFLAGS) ||
+ !(fp && fp->f_flags & O_NONBLOCK);
++
++ /*
++ * flush cache on last write release
++ */
++ if (CDROM_CAN(CDC_RAM) && !cdi->use_count && opened_for_data)
++ cdrom_close_write(cdi);
++
+ cdo->release(cdi);
+ if (cdi->use_count == 0) { /* last process that closes dev*/
+ if (opened_for_data &&
+@@ -1902,10 +2233,24 @@
+ }
+ }
+
++ /*
++ * queue command and wait for it to complete
++ */
+ ret = cdi->ops->generic_packet(cdi, cgc);
+- __copy_to_user(usense, cgc->sense, sizeof(*usense));
++
++ /*
++ * always copy back sense, command need not have failed for it to
++ * contain useful info
++ */
++ if (usense)
++ __copy_to_user(usense, cgc->sense, sizeof(*usense));
++
++ /*
++ * this really needs to be modified to copy back good bytes
++ */
+ if (!ret && cgc->data_direction == CGC_DATA_READ)
+ __copy_to_user(ubuf, cgc->buffer, cgc->buflen);
++
+ kfree(cgc->buffer);
+ return ret;
+ }
+@@ -2234,10 +2579,8 @@
+ return cdo->generic_packet(cdi, &cgc);
+ }
+
+-/* requires CD R/RW */
+-int cdrom_get_disc_info(kdev_t dev, disc_information *di)
++static int __cdrom_get_di(struct cdrom_device_info *cdi, disc_information *di)
+ {
+- struct cdrom_device_info *cdi = cdrom_find_device(dev);
+ struct cdrom_device_ops *cdo = cdi->ops;
+ struct cdrom_generic_command cgc;
+ int ret;
+@@ -2264,6 +2607,14 @@
+ return cdo->generic_packet(cdi, &cgc);
+ }
+
++/* requires CD R/RW */
++int cdrom_get_disc_info(kdev_t dev, disc_information *di)
++{
++ struct cdrom_device_info *cdi = cdrom_find_device(dev);
++
++ return __cdrom_get_di(cdi, di);
++}
++
+
+ /* return the last written block on the CD-R media. this is for the udf
+ file system. */
+@@ -2379,6 +2730,8 @@
+ EXPORT_SYMBOL(cdrom_mode_sense);
+ EXPORT_SYMBOL(init_cdrom_command);
+ EXPORT_SYMBOL(cdrom_find_device);
++EXPORT_SYMBOL(cdrom_get_media_event);
++EXPORT_SYMBOL(cdrom_is_mrw);
+
+ #ifdef CONFIG_SYSCTL
+
+@@ -2475,6 +2828,14 @@
+ for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
+ pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_DVD_RAM) != 0);
+
++ pos += sprintf(info+pos, "\nCan read MRW:");
++ for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
++ pos += sprintf(info+pos, "\t\t%d", CDROM_CAN(CDC_MRW) != 0);
++
++ pos += sprintf(info+pos, "\nCan write MRW:");
++ for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
++ pos += sprintf(info+pos, "\t\t%d", CDROM_CAN(CDC_MRW_W) != 0);
++
+ strcpy(info+pos,"\n\n");
+
+ return proc_dostring(ctl, write, filp, buffer, lenp);
+diff -ur -X /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.19-pre4/drivers/ide/ide-cd.c linux/drivers/ide/ide-cd.c
+--- /opt/kernel/linux-2.4.19-pre4/drivers/ide/ide-cd.c Tue Mar 26 09:52:55 2002
++++ linux/drivers/ide/ide-cd.c Mon Mar 25 17:40:39 2002
+@@ -694,12 +698,17 @@
+ case GPCMD_BLANK:
+ case GPCMD_FORMAT_UNIT:
+ case GPCMD_RESERVE_RZONE_TRACK:
+- wait = WAIT_CMD;
++ case GPCMD_CLOSE_TRACK:
++ case GPCMD_FLUSH_CACHE:
++ wait = ATAPI_WAIT_PC;
+ break;
+ default:
++ if (!pc->quiet)
++ printk("ide-cd: cmd 0x%x timed out\n",pc->c[0]);
+ wait = 0;
+ break;
+ }
++
+ return wait;
+ }
+
+@@ -745,7 +754,7 @@
+ (void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+
+ if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
+- ide_set_handler (drive, handler, WAIT_CMD, cdrom_timer_expiry);
++ ide_set_handler (drive, handler, ATAPI_WAIT_PC, cdrom_timer_expiry);
+ OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
+ return ide_started;
+ } else {
+@@ -1009,7 +1018,7 @@
+
+ /* Done moving data!
+ Wait for another interrupt. */
+- ide_set_handler(drive, &cdrom_read_intr, WAIT_CMD, NULL);
++ ide_set_handler(drive, &cdrom_read_intr, ATAPI_WAIT_PC, NULL);
+ return ide_started;
+ }
+
+@@ -1125,16 +1134,15 @@
+ pc.c[7] = (nframes >> 8);
+ pc.c[8] = (nframes & 0xff);
+ put_unaligned(cpu_to_be32(frame), (unsigned int *) &pc.c[2]);
+- pc.timeout = WAIT_CMD;
++ pc.timeout = ATAPI_WAIT_PC;
+
+ /* Send the command to the drive and return. */
+ return cdrom_transfer_packet_command(drive, &pc, &cdrom_read_intr);
+ }
+
+-
+ #define IDECD_SEEK_THRESHOLD (1000) /* 1000 blocks */
+ #define IDECD_SEEK_TIMER (5 * WAIT_MIN_SLEEP) /* 100 ms */
+-#define IDECD_SEEK_TIMEOUT WAIT_CMD /* 10 sec */
++#define IDECD_SEEK_TIMEOUT (2 * WAIT_CMD) /* 20 sec */
+
+ static ide_startstop_t cdrom_seek_intr (ide_drive_t *drive)
+ {
+@@ -1178,7 +1186,7 @@
+ pc.c[0] = GPCMD_SEEK;
+ put_unaligned(cpu_to_be32(frame), (unsigned int *) &pc.c[2]);
+
+- pc.timeout = WAIT_CMD;
++ pc.timeout = ATAPI_WAIT_PC;
+ return cdrom_transfer_packet_command(drive, &pc, &cdrom_seek_intr);
+ }
+
+@@ -1198,28 +1198,6 @@
+ return cdrom_start_packet_command (drive, 0, cdrom_start_seek_continuation);
+ }
+
+-static inline int cdrom_merge_requests(struct request *rq, struct request *nxt)
+-{
+- int ret = 1;
+-
+- /*
+- * partitions not really working, but better check anyway...
+- */
+- if (rq->cmd == nxt->cmd && rq->rq_dev == nxt->rq_dev) {
+- if (rq->cmd == WRITE)
+- printk("merged write\n");
+- rq->nr_sectors += nxt->nr_sectors;
+- rq->hard_nr_sectors += nxt->nr_sectors;
+- rq->bhtail->b_reqnext = nxt->bh;
+- rq->bhtail = nxt->bhtail;
+- list_del(&nxt->queue);
+- blkdev_release_request(nxt);
+- ret = 0;
+- }
+-
+- return ret;
+-}
+-
+ /*
+ * the current request will always be the first one on the list
+ */
+@@ -1229,13 +1217,31 @@
+ break;
+
+ nxt = blkdev_entry_to_request(entry);
++
++ if (rq->cmd != nxt->cmd)
++ break;
++ if (rq->rq_dev != nxt->rq_dev)
++ break;
+ if (rq->sector + rq->nr_sectors != nxt->sector)
+ break;
+- else if (rq->nr_sectors + nxt->nr_sectors > SECTORS_MAX)
++ if (rq->nr_sectors + nxt->nr_sectors >= SECTORS_MAX)
+ break;
+-
+- if (cdrom_merge_requests(rq, nxt))
++ if (rq->nr_segments + nxt->nr_segments > PRD_ENTRIES)
+ break;
++
++ /*
++ * ok to merge them
++ */
++ rq->nr_sectors += nxt->nr_sectors;
++ rq->hard_nr_sectors += nxt->nr_sectors;
++ rq->bhtail->b_reqnext = nxt->bh;
++ rq->bhtail = nxt->bhtail;
++
++ /*
++ * release nxt
++ */
++ blkdev_dequeue_request(nxt);
++ blkdev_release_request(nxt);
+ }
+
+ spin_unlock_irqrestore(&io_request_lock, flags);
+@@ -1399,7 +1405,7 @@
+ }
+
+ /* Now we wait for another interrupt. */
+- ide_set_handler (drive, &cdrom_pc_intr, WAIT_CMD, cdrom_timer_expiry);
++ ide_set_handler (drive, &cdrom_pc_intr, ATAPI_WAIT_PC, cdrom_timer_expiry);
+ return ide_started;
+ }
+
+@@ -1410,7 +1416,7 @@
+ struct packet_command *pc = (struct packet_command *)rq->buffer;
+
+ if (!pc->timeout)
+- pc->timeout = WAIT_CMD;
++ pc->timeout = ATAPI_WAIT_PC;
+
+ /* Send the command to the drive and return. */
+ return cdrom_transfer_packet_command(drive, pc, &cdrom_pc_intr);
+@@ -1624,7 +1630,7 @@
+ }
+
+ /* re-arm handler */
+- ide_set_handler(drive, &cdrom_write_intr, 5 * WAIT_CMD, NULL);
++ ide_set_handler(drive, &cdrom_write_intr, ATAPI_WAIT_PC, NULL);
+ return ide_started;
+ }
+
+@@ -1649,7 +1655,7 @@
+ pc.c[7] = (nframes >> 8) & 0xff;
+ pc.c[8] = nframes & 0xff;
+ put_unaligned(cpu_to_be32(frame), (unsigned int *)&pc.c[2]);
+- pc.timeout = 2 * WAIT_CMD;
++ pc.timeout = ATAPI_WAIT_PC;
+
+ return cdrom_transfer_packet_command(drive, &pc, cdrom_write_intr);
+ }
+@@ -2188,7 +2194,7 @@
+ ide_drive_t *drive = (ide_drive_t*) cdi->handle;
+
+ if (cgc->timeout <= 0)
+- cgc->timeout = WAIT_CMD;
++ cgc->timeout = ATAPI_WAIT_PC;
+
+ /* here we queue the commands from the uniform CD-ROM
+ layer. the packet must be complete, as we do not
+@@ -2200,6 +2206,7 @@
+ pc.quiet = cgc->quiet;
+ pc.timeout = cgc->timeout;
+ pc.sense = cgc->sense;
++
+ return cgc->stat = cdrom_queue_packet_command(drive, &pc);
+ }
+
+@@ -2385,37 +2392,49 @@
+ return 0;
+ }
+
++/*
++ * add logic to try GET_EVENT command first to check for media and tray
++ * status. this should be supported by newer cd-r/w and all DVD etc
++ * drives
++ */
+ static
+ int ide_cdrom_drive_status (struct cdrom_device_info *cdi, int slot_nr)
+ {
+ ide_drive_t *drive = (ide_drive_t*) cdi->handle;
++ struct media_event_desc med;
++ struct request_sense sense;
++ int stat;
+
+- if (slot_nr == CDSL_CURRENT) {
+- struct request_sense sense;
+- int stat = cdrom_check_status(drive, &sense);
+- if (stat == 0 || sense.sense_key == UNIT_ATTENTION)
+- return CDS_DISC_OK;
++ if (slot_nr != CDSL_CURRENT)
++ return -EINVAL;
+
+- if (sense.sense_key == NOT_READY && sense.asc == 0x04 &&
+- sense.ascq == 0x04)
+- return CDS_DISC_OK;
++ stat = cdrom_check_status(drive, &sense);
++ if (!stat || sense.sense_key == UNIT_ATTENTION)
++ return CDS_DISC_OK;
+
++ if (!cdrom_get_media_event(cdi, &med)) {
++ if (med.media_present)
++ return CDS_DISC_OK;
++ if (med.door_open)
++ return CDS_TRAY_OPEN;
++ }
+
+- /*
+- * If not using Mt Fuji extended media tray reports,
+- * just return TRAY_OPEN since ATAPI doesn't provide
+- * any other way to detect this...
+- */
+- if (sense.sense_key == NOT_READY) {
+- if (sense.asc == 0x3a && sense.ascq == 1)
+- return CDS_NO_DISC;
+- else
+- return CDS_TRAY_OPEN;
+- }
++ if (sense.sense_key == NOT_READY && sense.asc == 0x04 && sense.ascq == 0x04)
++ return CDS_DISC_OK;
+
+- return CDS_DRIVE_NOT_READY;
++ /*
++ * If not using Mt Fuji extended media tray reports,
++ * just return TRAY_OPEN since ATAPI doesn't provide
++ * any other way to detect this...
++ */
++ if (sense.sense_key == NOT_READY) {
++ if (sense.asc == 0x3a && sense.ascq == 1)
++ return CDS_NO_DISC;
++ else
++ return CDS_TRAY_OPEN;
+ }
+- return -EINVAL;
++
++ return CDS_DRIVE_NOT_READY;
+ }
+
+ static
+@@ -2523,7 +2542,8 @@
+ CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET |
+ CDC_IOCTLS | CDC_DRIVE_STATUS | CDC_CD_R |
+ CDC_CD_RW | CDC_DVD | CDC_DVD_R| CDC_DVD_RAM |
+- CDC_GENERIC_PACKET,
++ CDC_GENERIC_PACKET | CDC_MRW | CDC_MRW_W |
++ CDC_RAM,
+ generic_packet: ide_cdrom_packet,
+ };
+
+@@ -2558,6 +2578,10 @@
+ devinfo->mask |= CDC_PLAY_AUDIO;
+ if (!CDROM_CONFIG_FLAGS (drive)->close_tray)
+ devinfo->mask |= CDC_CLOSE_TRAY;
++ if (!CDROM_CONFIG_FLAGS(drive)->mrw)
++ devinfo->mask |= CDC_MRW;
++ if (!CDROM_CONFIG_FLAGS(drive)->mrw_w)
++ devinfo->mask |= CDC_MRW_W;
+
+ devinfo->de = devfs_register(drive->de, "cd", DEVFS_FL_DEFAULT,
+ HWIF(drive)->major, minor,
+@@ -2585,14 +2609,6 @@
+ size -= sizeof(cap->pad);
+ }
+
+- /* we have to cheat a little here. the packet will eventually
+- * be queued with ide_cdrom_packet(), which extracts the
+- * drive from cdi->handle. Since this device hasn't been
+- * registered with the Uniform layer yet, it can't do this.
+- * Same goes for cdi->ops.
+- */
+- cdi->handle = (ide_drive_t *) drive;
+- cdi->ops = &ide_cdrom_dops;
+ init_cdrom_command(&cgc, cap, size, CGC_DATA_UNKNOWN);
+ do { /* we seem to get stat=0x01,err=0x00 the first time (??) */
+ stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CAPABILITIES_PAGE, 0);
+@@ -2608,17 +2624,36 @@
+ struct cdrom_info *info = drive->driver_data;
+ struct cdrom_device_info *cdi = &info->devinfo;
+ struct atapi_capabilities_page cap;
+- int nslots = 1;
++ int nslots = 1, mrw_write = 0;
+
+- if (CDROM_CONFIG_FLAGS (drive)->nec260) {
++ if (CDROM_CONFIG_FLAGS (drive)->nec260 ||
++ !strcmp(drive->id->model,"STINGRAY 8422 IDE 8X CD-ROM 7-27-95")) {
+ CDROM_CONFIG_FLAGS (drive)->no_eject = 0;
+ CDROM_CONFIG_FLAGS (drive)->audio_play = 1;
+ return nslots;
+ }
+
++ /*
++ * we have to cheat a little here. the packet will eventually
++ * be queued with ide_cdrom_packet(), which extracts the
++ * drive from cdi->handle. Since this device hasn't been
++ * registered with the Uniform layer yet, it can't do this.
++ * Same goes for cdi->ops.
++ */
++ cdi->handle = (ide_drive_t *) drive;
++ cdi->ops = &ide_cdrom_dops;
++
+ if (ide_cdrom_get_capabilities(drive, &cap))
+ return 0;
+
++ if (!cdrom_is_mrw(cdi, &mrw_write)) {
++ CDROM_CONFIG_FLAGS(drive)->mrw = 1;
++ if (mrw_write) {
++ CDROM_CONFIG_FLAGS(drive)->mrw_w = 1;
++ CDROM_CONFIG_FLAGS(drive)->ram = 1;
++ }
++ }
++
+ if (cap.lock == 0)
+ CDROM_CONFIG_FLAGS (drive)->no_doorlock = 1;
+ if (cap.eject)
+@@ -2631,8 +2666,10 @@
+ CDROM_CONFIG_FLAGS (drive)->test_write = 1;
+ if (cap.dvd_ram_read || cap.dvd_r_read || cap.dvd_rom)
+ CDROM_CONFIG_FLAGS (drive)->dvd = 1;
+- if (cap.dvd_ram_write)
++ if (cap.dvd_ram_write) {
+ CDROM_CONFIG_FLAGS (drive)->dvd_ram = 1;
++ CDROM_CONFIG_FLAGS(drive)->ram = 1;
++ }
+ if (cap.dvd_r_write)
+ CDROM_CONFIG_FLAGS (drive)->dvd_r = 1;
+ if (cap.audio_play)
+@@ -2693,6 +2730,10 @@
+ (CDROM_CONFIG_FLAGS (drive)->cd_r)? "-R" : "",
+ (CDROM_CONFIG_FLAGS (drive)->cd_rw)? "/RW" : "");
+
++ if (CDROM_CONFIG_FLAGS(drive)->mrw || CDROM_CONFIG_FLAGS(drive)->mrw_w)
++ printk(" CD-MR%s",
++ CDROM_CONFIG_FLAGS(drive)->mrw_w ? "W" : "");
++
+ if (CDROM_CONFIG_FLAGS (drive)->is_changer)
+ printk (" changer w/%d slots", nslots);
+ else
+@@ -2726,14 +2767,9 @@
+ struct cdrom_info *info = drive->driver_data;
+ struct cdrom_device_info *cdi = &info->devinfo;
+ int minor = drive->select.b.unit << PARTN_BITS;
++ kdev_t cd_dev = MKDEV(HWIF(drive)->major, minor);
+ int nslots;
+
+- /*
+- * default to read-only always and fix latter at the bottom
+- */
+- set_device_ro(MKDEV(HWIF(drive)->major, minor), 0);
+- set_blocksize(MKDEV(HWIF(drive)->major, minor), CD_FRAMESIZE);
+-
+ drive->special.all = 0;
+ drive->ready_stat = 0;
+
+@@ -2850,8 +2886,11 @@
+
+ nslots = ide_cdrom_probe_capabilities (drive);
+
+- if (CDROM_CONFIG_FLAGS(drive)->dvd_ram)
+- set_device_ro(MKDEV(HWIF(drive)->major, minor), 0);
++ /*
++ * set correct block size and read-only for non-ram media
++ */
++ set_blocksize(cd_dev, CD_FRAMESIZE);
++ set_device_ro(cd_dev, !CDROM_CONFIG_FLAGS(drive)->ram);
+
+ if (ide_cdrom_register (drive, nslots)) {
+ printk ("%s: ide_cdrom_setup failed to register device with the cdrom driver.\n", drive->name);
+diff -ur -X /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.19-pre4/drivers/ide/ide-cd.h linux/drivers/ide/ide-cd.h
+--- /opt/kernel/linux-2.4.19-pre4/drivers/ide/ide-cd.h Tue Mar 26 09:52:55 2002
++++ linux/drivers/ide/ide-cd.h Tue Mar 26 09:55:15 2002
+@@ -35,6 +35,11 @@
+ #define NO_DOOR_LOCKING 0
+ #endif
+
++/*
++ * typical timeout for packet command
++ */
++#define ATAPI_WAIT_PC (60 * HZ)
++
+ /************************************************************************/
+
+ #define SECTOR_BITS 9
+@@ -75,6 +80,9 @@
+ __u8 dvd : 1; /* Drive is a DVD-ROM */
+ __u8 dvd_r : 1; /* Drive can write DVD-R */
+ __u8 dvd_ram : 1; /* Drive can write DVD-RAM */
++ __u8 mrw : 1; /* drive can read mrw */
++ __u8 mrw_w : 1; /* drive can write mrw */
++ __u8 ram : 1; /* generic WRITE (dvd-ram/mrw) */
+ __u8 test_write : 1; /* Drive can fake writes */
+ __u8 supp_disc_present : 1; /* Changer can report exact contents
+ of slots. */
+diff -ur -X /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.19-pre4/drivers/ide/ide-dma.c linux/drivers/ide/ide-dma.c
+--- /opt/kernel/linux-2.4.19-pre4/drivers/ide/ide-dma.c Tue Mar 26 09:52:55 2002
++++ linux/drivers/ide/ide-dma.c Mon Mar 25 08:42:18 2002
+@@ -204,25 +204,6 @@
+ #endif /* CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
+
+ /*
+- * Our Physical Region Descriptor (PRD) table should be large enough
+- * to handle the biggest I/O request we are likely to see. Since requests
+- * can have no more than 256 sectors, and since the typical blocksize is
+- * two or more sectors, we could get by with a limit of 128 entries here for
+- * the usual worst case. Most requests seem to include some contiguous blocks,
+- * further reducing the number of table entries required.
+- *
+- * The driver reverts to PIO mode for individual requests that exceed
+- * this limit (possible with 512 byte blocksizes, eg. MSDOS f/s), so handling
+- * 100% of all crazy scenarios here is not necessary.
+- *
+- * As it turns out though, we must allocate a full 4KB page for this,
+- * so the two PRD tables (ide0 & ide1) will each get half of that,
+- * allowing each to have about 256 entries (8 bytes each) from this.
+- */
+-#define PRD_BYTES 8
+-#define PRD_ENTRIES (PAGE_SIZE / (2 * PRD_BYTES))
+-
+-/*
+ * dma_intr() is the handler for disk read/write DMA interrupts
+ */
+ ide_startstop_t ide_dma_intr (ide_drive_t *drive)
+diff -ur -X /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.19-pre4/drivers/scsi/sr.c linux/drivers/scsi/sr.c
+--- /opt/kernel/linux-2.4.19-pre4/drivers/scsi/sr.c Tue Mar 26 09:52:56 2002
++++ linux/drivers/scsi/sr.c Tue Mar 26 08:00:47 2002
+@@ -128,7 +128,8 @@
+ CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO |
+ CDC_RESET | CDC_IOCTLS | CDC_DRIVE_STATUS |
+ CDC_CD_R | CDC_CD_RW | CDC_DVD | CDC_DVD_R |
+- CDC_DVD_RAM | CDC_GENERIC_PACKET,
++ CDC_DVD_RAM | CDC_GENERIC_PACKET | CDC_MRW |
++ CDC_MRW_W | CDC_RAM,
+ generic_packet: sr_packet,
+ };
+
+@@ -690,7 +691,7 @@
+ {
+ unsigned char cmd[6];
+ unsigned char *buffer;
+- int rc, n;
++ int rc, n, mrw_write = 0, mrw = 1;
+
+ static char *loadmech[] =
+ {
+@@ -716,7 +717,7 @@
+ cmd[2] = 0x2a;
+ cmd[4] = 128;
+ cmd[3] = cmd[5] = 0;
+- rc = sr_do_ioctl(i, cmd, buffer, 128, 1, SCSI_DATA_READ, NULL, SR_TIMEOUT);
++ rc = sr_do_ioctl(i, cmd, buffer, 128, 1, SCSI_DATA_READ, NULL, 0);
+
+ if (rc) {
+ /* failed, drive doesn't have capabilities mode page */
+@@ -728,6 +729,15 @@
+ printk("sr%i: scsi-1 drive\n", i);
+ return;
+ }
++
++ if (cdrom_is_mrw(&scsi_CDs[i].cdi, &mrw_write)) {
++ mrw = 0;
++ scsi_CDs[i].cdi.mask |= CDC_MRW;
++ scsi_CDs[i].cdi.mask |= CDC_MRW_W;
++ }
++ if (!mrw_write)
++ scsi_CDs[i].cdi.mask |= CDC_MRW_W;
++
+ n = buffer[3] + 4;
+ scsi_CDs[i].cdi.speed = ((buffer[n + 8] << 8) + buffer[n + 9]) / 176;
+ scsi_CDs[i].readcd_known = 1;
+@@ -777,7 +785,14 @@
+ /*else I don't think it can close its tray
+ scsi_CDs[i].cdi.mask |= CDC_CLOSE_TRAY; */
+
++ /*
++ * if DVD-RAM of MRW-W, we are randomly writeable
++ */
++ if ((scsi_CDs[i].cdi.mask & (CDC_DVD_RAM | CDC_MRW_W)) != (CDC_DVD_RAM | CDC_MRW_W))
++ scsi_CDs[i].device->writeable = 1;
++
+ scsi_free(buffer, 512);
++
+ }
+
+ /*
+diff -ur -X /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.19-pre4/include/linux/cdrom.h linux/include/linux/cdrom.h
+--- /opt/kernel/linux-2.4.19-pre4/include/linux/cdrom.h Thu Nov 22 20:47:04 2001
++++ linux/include/linux/cdrom.h Tue Mar 26 09:55:09 2002
+@@ -5,7 +5,7 @@
+ * 1994, 1995 Eberhard Moenkeberg, emoenke@gwdg.de
+ * 1996 David van Leeuwen, david@tm.tno.nl
+ * 1997, 1998 Erik Andersen, andersee@debian.org
+- * 1998-2000 Jens Axboe, axboe@suse.de
++ * 1998-2002 Jens Axboe, axboe@suse.de
+ */
+
+ #ifndef _LINUX_CDROM_H
+@@ -387,6 +387,9 @@
+ #define CDC_DVD 0x8000 /* drive is a DVD */
+ #define CDC_DVD_R 0x10000 /* drive can write DVD-R */
+ #define CDC_DVD_RAM 0x20000 /* drive can write DVD-RAM */
++#define CDC_MRW 0x40000 /* drive can read MRW */
++#define CDC_MRW_W 0x80000 /* drive can write MRW */
++#define CDC_RAM 0x100000 /* ok to open WRITE */
+
+ /* drive status possibilities returned by CDROM_DRIVE_STATUS ioctl */
+ #define CDS_NO_INFO 0 /* if not implemented */
+@@ -714,16 +717,61 @@
+ __u8 asb[46];
+ };
+
+-#ifdef __KERNEL__
+-#include <linux/devfs_fs_kernel.h>
++/*
++ * feature profile
++ */
++#define CDF_MRW 0x28
++
++/*
++ * media status bits
++ */
++#define CDM_MRW_NOTMRW 0
++#define CDM_MRW_BGFORMAT_INACTIVE 1
++#define CDM_MRW_BGFORMAT_ACTIVE 2
++#define CDM_MRW_BGFORMAT_COMPLETE 3
++
++/*
++ * mrw address spaces
++ */
++#define MRW_LBA_DMA 0
++#define MRW_LBA_GAA 1
++
++/*
++ * mrw mode pages (first is deprecated) -- probed at init time and
++ * cdi->mrw_mode_page is set
++ */
++#define MRW_MODE_PC_PRE1 0x2c
++#define MRW_MODE_PC 0x03
+
+-struct cdrom_write_settings {
+- unsigned char fpacket; /* fixed/variable packets */
+- unsigned long packet_size; /* write out this number of packets */
+- unsigned long nwa; /* next writeable address */
+- unsigned char writeable; /* cdrom is writeable */
++struct mrw_feature_desc {
++ __u16 feature_code;
++#if defined(__BIG_ENDIAN_BITFIELD)
++ __u8 reserved1 : 2;
++ __u8 feature_version : 4;
++ __u8 persistent : 1;
++ __u8 curr : 1;
++#elif defined(__LITTLE_ENDIAN_BITFIELD)
++ __u8 curr : 1;
++ __u8 persistent : 1;
++ __u8 feature_version : 4;
++ __u8 reserved1 : 2;
++#endif
++ __u8 add_len;
++#if defined(__BIG_ENDIAN_BITFIELD)
++ __u8 reserved2 : 7;
++ __u8 write : 1;
++#elif defined(__LITTLE_ENDIAN_BITFIELD)
++ __u8 write : 1;
++ __u8 reserved2 : 7;
++#endif
++ __u8 reserved3;
++ __u8 reserved4;
++ __u8 reserved5;
+ };
+
++#ifdef __KERNEL__
++#include <linux/devfs_fs_kernel.h>
++
+ /* Uniform cdrom data structures for cdrom.c */
+ struct cdrom_device_info {
+ struct cdrom_device_ops *ops; /* link to device_ops */
+@@ -744,7 +792,9 @@
+ /* per-device flags */
+ __u8 sanyo_slot : 2; /* Sanyo 3 CD changer support */
+ __u8 reserved : 6; /* not used yet */
+- struct cdrom_write_settings write;
++
++ int (*exit)(struct cdrom_device_info *);
++ int mrw_mode_page;
+ };
+
+ struct cdrom_device_ops {
+@@ -819,6 +869,8 @@
+ void *buffer, int len, int type);
+ extern struct cdrom_device_info *cdrom_find_device(kdev_t dev);
+
++#endif /* __KERNEL__ */
++
+ typedef struct {
+ __u16 disc_information_length;
+ #if defined(__BIG_ENDIAN_BITFIELD)
+@@ -842,9 +894,13 @@
+ __u8 did_v : 1;
+ __u8 dbc_v : 1;
+ __u8 uru : 1;
+- __u8 reserved2 : 5;
++ __u8 reserved2 : 2;
++ __u8 dbit : 1;
++ __u8 mrw_status : 2;
+ #elif defined(__LITTLE_ENDIAN_BITFIELD)
+- __u8 reserved2 : 5;
++ __u8 mrw_status : 2;
++ __u8 dbit : 1;
++ __u8 reserved2 : 2;
+ __u8 uru : 1;
+ __u8 dbc_v : 1;
+ __u8 did_v : 1;
+@@ -901,10 +957,6 @@
+ __u32 last_rec_address;
+ } track_information;
+
+-extern int cdrom_get_disc_info(kdev_t dev, disc_information *di);
+-extern int cdrom_get_track_info(kdev_t dev, __u16 track, __u8 type,
+- track_information *ti);
+-
+ /* The SCSI spec says there could be 256 slots. */
+ #define CDROM_MAX_SLOTS 256
+
+@@ -1053,6 +1105,51 @@
+ __u8 reserved3;
+ } rpc_state_t;
+
+-#endif /* End of kernel only stuff */
++struct feature_header {
++ __u32 data_len;
++ __u8 reserved1;
++ __u8 reserved2;
++ __u16 curr_profile;
++};
++
++struct event_header {
++ __u16 data_len;
++#if defined(__BIG_ENDIAN_BITFIELD)
++ __u8 nea : 1;
++ __u8 reserved1 : 4;
++ __u8 notification_class : 3;
++#elif defined(__LITTLE_ENDIAN_BITFIELD)
++ __u8 notification_class : 3;
++ __u8 reserved1 : 4;
++ __u8 nea : 1;
++#endif
++ __u8 supp_event_class;
++};
++
++struct media_event_desc {
++#if defined(__BIG_ENDIAN_BITFIELD)
++ __u8 reserved1 : 4;
++ __u8 media_event_code : 4;
++ __u8 reserved2 : 6;
++ __u8 media_present : 1;
++ __u8 door_open : 1;
++#elif defined(__LITTLE_ENDIAN_BITFIELD)
++ __u8 media_event_code : 4;
++ __u8 reserved1 : 4;
++ __u8 door_open : 1;
++ __u8 media_present : 1;
++ __u8 reserved2 : 6;
++#endif
++ __u8 start_slot;
++ __u8 end_slot;
++};
++
++#ifdef __KERNEL__
++extern int cdrom_get_disc_info(kdev_t dev, disc_information *di);
++extern int cdrom_get_track_info(kdev_t dev, __u16 track, __u8 type,
++ track_information *ti);
++extern int cdrom_get_media_event(struct cdrom_device_info *cdi, struct media_event_desc *med);
++extern int cdrom_is_mrw(struct cdrom_device_info *cdi, int *write);
++#endif /* __KERNEL__ */
+
+ #endif /* _LINUX_CDROM_H */
+diff -ur -X /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.19-pre4/include/linux/ide.h linux/include/linux/ide.h
+--- /opt/kernel/linux-2.4.19-pre4/include/linux/ide.h Tue Mar 26 09:52:58 2002
++++ linux/include/linux/ide.h Mon Mar 25 11:55:23 2002
+@@ -259,6 +259,25 @@
+ #endif
+
+ /*
++ * Our Physical Region Descriptor (PRD) table should be large enough
++ * to handle the biggest I/O request we are likely to see. Since requests
++ * can have no more than 256 sectors, and since the typical blocksize is
++ * two or more sectors, we could get by with a limit of 128 entries here for
++ * the usual worst case. Most requests seem to include some contiguous blocks,
++ * further reducing the number of table entries required.
++ *
++ * The driver reverts to PIO mode for individual requests that exceed
++ * this limit (possible with 512 byte blocksizes, eg. MSDOS f/s), so handling
++ * 100% of all crazy scenarios here is not necessary.
++ *
++ * As it turns out though, we must allocate a full 4KB page for this,
++ * so the two PRD tables (ide0 & ide1) will each get half of that,
++ * allowing each to have about 256 entries (8 bytes each) from this.
++ */
++#define PRD_BYTES 8
++#define PRD_ENTRIES (PAGE_SIZE / (2 * PRD_BYTES))
++
++/*
+ * hwif_chipset_t is used to keep track of the specific hardware
+ * chipset used by each IDE interface, if known.
+ */
+diff -ur -X /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.19-pre4/include/linux/udf_fs.h linux/include/linux/udf_fs.h
+--- /opt/kernel/linux-2.4.19-pre4/include/linux/udf_fs.h Tue Mar 26 09:52:58 2002
++++ linux/include/linux/udf_fs.h Mon Mar 25 08:50:14 2002
+@@ -30,6 +30,7 @@
+ * HISTORY
+ *
+ */
++#include <linux/config.h>
+
+ #ifndef _UDF_FS_H
+ #define _UDF_FS_H 1