diff -Naur linux-2.4.22.orig/drivers/block/pktcdvd.c linux-2.4.22/drivers/block/pktcdvd.c
--- linux-2.4.22.orig/drivers/block/pktcdvd.c	2003-10-28 22:02:45.000000000 +0000
+++ linux-2.4.22/drivers/block/pktcdvd.c	2003-10-28 09:12:53.000000000 +0000
@@ -132,7 +132,7 @@
 /*
  * 32 buffers of 2048 bytes
  */
-#define PACKET_MAX_SIZE		32
+#define PACKET_MAX_MAX_SIZE		32
 
 #define NEXT_BH(bh, nbh)	\
 	 (((bh)->b_rsector + ((bh)->b_size >> 9)) == (nbh)->b_rsector)
@@ -792,7 +792,7 @@
 	up(&pd->cache_sync_mutex);
 }
 
-static int pkt_index_bhs(struct buffer_head **bhs)
+static int pkt_index_bhs(struct buffer_head **bhs, int packet_max_size)
 {
 	struct buffer_head *bh;
 	int index;
@@ -802,7 +802,7 @@
 	 * now finish pending reads and connect the chain of buffers
 	 */
 	index = 0;
-	while (index < PACKET_MAX_SIZE) {
+	while (index < packet_max_size) {
 		bh = bhs[index];
 
 		/*
@@ -858,7 +858,7 @@
 	unsigned long start_s, end_s, sector;
 	struct buffer_head *bh;
 	unsigned int sectors, index;
-	struct buffer_head *bhs[PACKET_MAX_SIZE];
+	struct buffer_head *bhs[PACKET_MAX_MAX_SIZE];
 
 	memset(bhs, 0, sizeof(bhs));
 
@@ -915,7 +915,7 @@
 		sector += bh->b_size >> 9;
 	}
 
-	index = pkt_index_bhs(bhs);
+	index = pkt_index_bhs(bhs, pd->settings.packet_max_size);
 #if 0
 	if (!index)
 		goto kill_it;
@@ -930,7 +930,7 @@
 
 	VPRINTK("unlocked last %lu\n", rq->bhtail->b_rsector);
 	if (pkt_init_rq(pd, rq)) {
-		for (index = 0; index < PACKET_MAX_SIZE; index++) {
+		for (index = 0; index < pd->settings.packet_max_size; index++) {
 			bh = bhs[index];
 			printk("[%d] %lu %d (%p -> %p)\n", index, bh->b_rsector,
 					bh->b_size, bh, bh->b_reqnext);
@@ -955,7 +955,7 @@
 	 * for now, just kill entire request and hope for the best...
 	 */
 kill_it:
-	for (index = 0; index < PACKET_MAX_SIZE; index++) {
+	for (index = 0; index < pd->settings.packet_max_size; index++) {
 		bh = bhs[index];
 		buffer_IO_error(bh);
 		if (bh->b_list == PKT_BUF_LIST)
@@ -1005,7 +1005,7 @@
 {
 #if 0
 	struct super_block *sb = get_super(pd->pkt_dev);
-	struct buffer_head *bhs[PACKET_MAX_SIZE], *bh, *obh;
+	struct buffer_head *bhs[PACKET_MAX_MAX_SIZE], *bh, *obh;
 	unsigned long old_block, new_block, sector;
 	int i, sectors;
 
@@ -1028,7 +1028,7 @@
 
 	sectors = 0;
 	sector = new_block * (rq->bh->b_size >> 9);
-	for (i = 0; i < PACKET_MAX_SIZE; i++) {
+	for (i = 0; i < pd->settings.packet_max_size; i++) {
 		bh = bhs[i];
 
 		/*
@@ -1146,7 +1146,7 @@
 	}
 
 	if (!pkt_do_request(pd, rq)) {
-		atomic_add(PACKET_MAX_SIZE, &pd->wrqcnt);
+		atomic_add(pd->settings.packet_max_size, &pd->wrqcnt);
 		down(&pd->cache_sync_mutex);
 		pkt_inject_request(q, rq);
 		pd->unflushed_writes = 1;
@@ -1378,6 +1378,10 @@
 	char buffer[128];
 	int ret, size;
 
+	/* doesn't apply to DVD+RW (?) */
+	if (pd->mmc3_profile == 0x1a)
+		return 0;
+
 	memset(buffer, 0, sizeof(buffer));
 	init_cdrom_command(&cgc, buffer, sizeof(*wp), CGC_DATA_READ);
 	cgc.sense = &sense;
@@ -1483,6 +1487,17 @@
  */
 static int pkt_good_disc(struct pktcdvd_device *pd, disc_information *di)
 {
+	switch (pd->mmc3_profile) {
+		case 0x0a: /* CD-RW */
+		case 0xffff: /* MMC3 not supported ? */
+			break;
+		case 0x1a: /* DVD+RW */
+			return 0;
+		default:
+			printk("pktcdvd: Wrong disc profile (%x)\n", pd->mmc3_profile);
+			return 1;
+	}
+
 	/*
 	 * for disc type 0xff we should probably reserve a new track.
 	 * but i'm not sure, should we leave this to user apps? probably.
@@ -1512,10 +1527,18 @@
 
 static int pkt_probe_settings(struct pktcdvd_device *pd)
 {
+	struct cdrom_generic_command cgc;
+	unsigned char buf [12];
 	disc_information di;
 	track_information ti;
 	int ret, track;
 
+	init_cdrom_command(&cgc, buf, 8, CGC_DATA_READ);
+	cgc.cmd[0] = GPCMD_GET_CONFIGURATION;
+	cgc.cmd[8] = 8;
+	ret = pd->cdi->ops->generic_packet(pd->cdi, &cgc);
+	pd->mmc3_profile = ret ? 0xffff : buf[6]<<8|buf[7];
+
 	memset(&di, 0, sizeof(disc_information));
 	memset(&ti, 0, sizeof(track_information));
 
@@ -1527,8 +1550,10 @@
 	pd->disc_status = di.disc_status;
 	pd->track_status = di.border_status;
 
-	if (pkt_good_disc(pd, &di))
+	if (pkt_good_disc(pd, &di)) {
+		printk("not a good disc\n");
 		return -ENXIO;
+	}
 
 	printk("pktcdvd: inserted media is CD-R%s\n", di.erasable ? "W" : "");
 	pd->type = di.erasable ? PACKET_CDRW : PACKET_CDR;
@@ -1548,11 +1573,16 @@
 	 * we keep packet size in 512 byte units, makes it easier to
 	 * deal with request calculations.
 	 */
-	pd->settings.size = be32_to_cpu(ti.fixed_packet_size) << 2;
-	if (pd->settings.size == 0) {
+	pd->settings.packet_max_size = be32_to_cpu(ti.fixed_packet_size);
+	if (pd->settings.packet_max_size == 0) {
 		printk("pktcdvd: detected zero packet size!\n");
-		pd->settings.size = 128;
+		pd->settings.packet_max_size = PACKET_MAX_MAX_SIZE;
+	}
+	if (pd->settings.packet_max_size > PACKET_MAX_MAX_SIZE) {
+		printk("pktcdvd: packet size too large\n");
+		return -ENXIO;
 	}
+	pd->settings.size = pd->settings.packet_max_size << 2;
 	pd->settings.fp = ti.fp;
 	pd->offset = (be32_to_cpu(ti.track_start) << 2) & (pd->settings.size - 1);
 
@@ -1656,9 +1686,9 @@
 }
 
 /*
- * Returns drive current write speed
+ * Returns drive maximum write speed
  */
-static int pkt_get_speed(struct pktcdvd_device *pd)
+static int pkt_get_max_speed(struct pktcdvd_device *pd, unsigned *speed)
 {
 	struct cdrom_generic_command cgc;
 	struct request_sense sense;
@@ -1680,17 +1710,13 @@
 		}
 	}
 
-	/* find out the current write speed selected
-	 * there are an obsoleted field for older drives (offset 20),
-	 * and a new field for newer (high-speed) drives (offset 28).
-	 */
-
+	/* find out the maximum write speed */
 	if (buf[pd->mode_offset+9] >= 28)
-		offset = pd->mode_offset + 36;
+		offset = pd->mode_offset + 42;
 	else
 		offset = pd->mode_offset + 28;
 
-	pd->speed = ((buf[offset] << 8) | buf[offset + 1]) / 0xb0;
+	*speed = ((buf[offset] << 8) | buf[offset + 1]) / 0xb0;
 	return 0;
 }
 
@@ -1789,11 +1815,10 @@
 /*
  * speed is given as the normal factor, e.g. 4 for 4x
  */
-static int pkt_set_speed(struct pktcdvd_device *pd, unsigned write_speed)
+static int pkt_set_speed(struct pktcdvd_device *pd, unsigned write_speed, unsigned read_speed)
 {
 	struct cdrom_generic_command cgc;
 	struct request_sense sense;
-	unsigned read_speed;
 	int ret;
 
 	/*
@@ -1804,7 +1829,7 @@
 	 */
 	write_speed = write_speed * 0xb1; /* should be 176.4, but CD-RWs rounds down */
 	write_speed = min_t(unsigned, write_speed, 0xffff);
-	read_speed = (write_speed * 3) >> 1;
+	read_speed = read_speed * 0xb1;
 	read_speed = min_t(unsigned, read_speed, 0xffff);
 
 	init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);
@@ -1823,9 +1848,11 @@
 /*
  * Give me full power, Captain
  */
-static int pkt_adjust_speed(struct pktcdvd_device *pd, int speed)
+static int pkt_adjust_speed(struct pktcdvd_device *pd, int write_speed, int read_speed)
 {
+#if 0
 	disc_information dummy;
+#endif
 	int ret;
 
 	/*
@@ -1835,10 +1862,16 @@
 	 * command (besides, we also use the old set speed command,
 	 * not the streaming feature).
 	 */
-	if ((ret = pkt_set_speed(pd, speed)))
+	if ((ret = pkt_set_speed(pd, write_speed, read_speed)))
 		return ret;
 
 	/*
+	 * We don't read back the speed once we've set it, because
+	 * I can't see how to discover the read speed; also, nothing
+	 * uses this information anywhere
+	 */
+#if 0
+	/*
 	 * just do something with the disc -- next read will contain the
 	 * maximum speed with this media
 	 */
@@ -1849,8 +1882,9 @@
 		printk("pktcdvd: failed get speed\n");
 		return ret;
 	}
+#endif
 
-	DPRINTK("pktcdvd: speed (R/W) %u/%u\n", (pd->speed * 3) / 2, pd->speed);
+	DPRINTK("pktcdvd: speed (R/W) %u/%u\n", read_speed, write_speed);
 	return 0;
 }
 
@@ -1875,7 +1909,7 @@
 static int pkt_open_write(struct pktcdvd_device *pd)
 {
 	int ret;
-	unsigned int speed;
+	unsigned int write_speed, read_speed;
 
 	if ((ret = pkt_probe_settings(pd))) {
 		DPRINTK("pktcdvd: %s failed probe\n", pd->name);
@@ -1889,10 +1923,20 @@
 
 	(void) pkt_write_caching(pd, USE_WCACHING);
 
-	ret = pkt_media_speed(pd, &speed);
-	speed = ret ? 16 : speed;
+	switch (pd->mmc3_profile) {
+		case 0x1a: /* dvd+rw */
+			if ((ret = pkt_get_max_speed(pd, &write_speed)))
+				write_speed = 16;
+			read_speed = write_speed;
+			break;
+		default:
+			if ((ret = pkt_media_speed(pd, &write_speed)))
+				write_speed = 16;
+			read_speed = (write_speed * 3) / 2;
+			break;
+	}
 
-	if ((ret = pkt_adjust_speed(pd, speed))) {
+	if ((ret = pkt_adjust_speed(pd, write_speed, read_speed))) {
 		DPRINTK("pktcdvd: %s couldn't set write speed\n", pd->name);
 		return -EIO;
 	}
@@ -1916,6 +1960,7 @@
 		return -ENXIO;
 
 	pd->bdev = bdget(kdev_t_to_nr(pd->dev));
+
 	if (!pd->bdev) {
 		printk("pktcdvd: can't find cdrom block device\n");
 		return -ENXIO;
@@ -1938,7 +1983,7 @@
 			return ret;
 		pkt_mark_readonly(pd, 0);
 	} else {
-		(void) pkt_adjust_speed(pd, 0xffff);
+		(void) pkt_adjust_speed(pd, 0xffff, 0xffff);
 		pkt_mark_readonly(pd, 1);
 	}
 
@@ -1963,7 +2008,7 @@
 	if (flush && pkt_flush_cache(pd))
 		DPRINTK("pktcdvd: %s not flushing cache\n", pd->name);
 
-	pkt_set_speed(pd, 0xffff);
+	pkt_set_speed(pd, 0xffff, 0xffff);
 
 	if (pd->bdev) {
 		blkdev_put(pd->bdev, BDEV_FILE);
@@ -2378,7 +2423,7 @@
 	atomic_set(&pd->cdrw.free_bh, 0);
 
 	spin_lock_init(&pd->lock);
-	if (pkt_grow_bhlist(pd, PACKET_MAX_SIZE) < PACKET_MAX_SIZE) {
+	if (pkt_grow_bhlist(pd, PACKET_MAX_MAX_SIZE) < PACKET_MAX_MAX_SIZE) {
 		MOD_DEC_USE_COUNT;
 		printk("pktcdvd: not enough memory for buffers\n");
 		return -ENOMEM;
@@ -2422,7 +2467,7 @@
 		printk("pktcdvd: can't start kernel thread\n");
 		blk_cleanup_queue(&pd->cdrw.r_queue);
 		pkt_shrink_stacked_bhlist(pd);
-		pkt_shrink_bhlist(pd, PACKET_MAX_SIZE);
+		pkt_shrink_bhlist(pd, PACKET_MAX_MAX_SIZE);
 		memset(pd, 0, sizeof(*pd));
 		return -EBUSY;
 	}
@@ -2494,8 +2539,8 @@
 	invalidate_device(pd->pkt_dev, 1);
 
 	pkt_shrink_stacked_bhlist(pd);
-	if ((ret = pkt_shrink_bhlist(pd, PACKET_MAX_SIZE)) != PACKET_MAX_SIZE)
-		printk("pktcdvd: leaked %d buffers\n", PACKET_MAX_SIZE - ret);
+	if ((ret = pkt_shrink_bhlist(pd, PACKET_MAX_MAX_SIZE)) != PACKET_MAX_MAX_SIZE)
+		printk("pktcdvd: leaked %d buffers\n", pd->settings.packet_max_size - ret);
 
 	blk_cleanup_queue(&pd->cdrw.r_queue);
 	remove_proc_entry(pd->name, pkt_proc);
diff -Naur linux-2.4.22.orig/drivers/scsi/sr_vendor.c linux-2.4.22/drivers/scsi/sr_vendor.c
--- linux-2.4.22.orig/drivers/scsi/sr_vendor.c	2003-10-28 22:03:16.000000000 +0000
+++ linux-2.4.22/drivers/scsi/sr_vendor.c	2003-10-28 08:20:28.000000000 +0000
@@ -110,6 +110,9 @@
 		    default:
 			scsi_CDs[minor].cdi.mask |= CDC_DVD_RAM;
 			scsi_CDs[minor].device->writeable = 0;
+			break;
+		    case 0x0A: /* CD-RW */
+			scsi_CDs[minor].device->writeable = 1;		
 		}
 	}
 	scsi_CDs[minor].mmc3_profile = mmc3_profile;
diff -Naur linux-2.4.22.orig/include/linux/pktcdvd.h linux-2.4.22/include/linux/pktcdvd.h
--- linux-2.4.22.orig/include/linux/pktcdvd.h	2003-10-28 22:02:45.000000000 +0000
+++ linux-2.4.22/include/linux/pktcdvd.h	2003-10-28 08:20:28.000000000 +0000
@@ -132,6 +132,7 @@
 
 struct packet_settings
 {
+	__u16			packet_max_size;
 	__u8			size;		/* packet size in frames */
 	__u8			fp;		/* fixed packets */
 	__u8			link_loss;	/* the rest is specified
@@ -170,6 +171,7 @@
 	__u8				mode_offset;	/* 0 / 8 */
 	__u8				type;
 	unsigned long			flags;
+	__u16				mmc3_profile;
 	__u8				disc_status;
 	__u8				track_status;	/* last one */
 	__u32				nwa;	/* next writable address */
