diff --git a/drivers/cdrom/Kconfig b/drivers/cdrom/Kconfig
index 4b12e90..8bfdedf 100644
--- a/drivers/cdrom/Kconfig
+++ b/drivers/cdrom/Kconfig
@@ -119,6 +119,20 @@ config MCDX
To compile this driver as a module, choose M here: the
module will be called mcdx.
+config MITSUMI
+ tristate "New Mitsumi CDROM support"
+ depends on CD_NO_IDESCSI
+ ---help---
+ Use this driver if you want to be able to use your Mitsumi LU002S,
+ LU005S, LU006S, FX001 or FX001D CD-ROM drive.
+
+ If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM
+ file system support" below, because that's the file system used on
+ CD-ROMs.
+
+ To compile this driver as a module, choose M here: the
+ module will be called mitsumi.
+
config OPTCD
tristate "Optics Storage DOLPHIN 8000AT CDROM support"
depends on CD_NO_IDESCSI
diff --git a/drivers/cdrom/Makefile b/drivers/cdrom/Makefile
index d1d1e5a..317d887 100644
--- a/drivers/cdrom/Makefile
+++ b/drivers/cdrom/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_CM206) += cm206.o cdrom.o
obj-$(CONFIG_GSCD) += gscd.o
obj-$(CONFIG_ISP16_CDI) += isp16.o
obj-$(CONFIG_MCDX) += mcdx.o cdrom.o
+obj-$(CONFIG_MITSUMI) += mitsumi.o cdrom.o
obj-$(CONFIG_OPTCD) += optcd.o
obj-$(CONFIG_SBPCD) += sbpcd.o cdrom.o
obj-$(CONFIG_SJCD) += sjcd.o
diff --git a/drivers/cdrom/mitsumi.c b/drivers/cdrom/mitsumi.c
new file mode 100644
index 0000000..79d95d0
--- /dev/null
+++ b/drivers/cdrom/mitsumi.c
@@ -0,0 +1,1026 @@
+/*
+ * drivers/cdrom/mitsumi.c - Mitsumi legacy CD-ROM Driver for Linux
+ *
+ * Copyright (C) 1995-1996 Heiko Schlittermann
+ * Copyright (C) 2007 Pekka Enberg
+ * Copyright (C) 2007 Rene Herman
+ *
+ * This file is released under the GPLv2.
+ */
+
+#include <linux/bcd.h>
+#include <linux/blkdev.h>
+#include <linux/cdrom.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/isa.h>
+#include <linux/major.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+
+MODULE_DESCRIPTION("Mitsumi legacy CD-ROM Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_BLOCKDEV_MAJOR(MITSUMI_CDROM_MAJOR);
+
+#define NR_DRIVES 1
+
+static unsigned long port[NR_DRIVES];
+static unsigned int irq[NR_DRIVES];
+
+module_param_array(port, ulong, NULL, 0444);
+module_param_array(irq, uint, NULL, 0444);
+
+/*
+ * The known drive commands
+ */
+enum { /* LU002S LU005S LU006S FX001 FX001D */
+ CMD_GET_VOLUME_INFO = 0x10, /* . Y Y Y Y */
+ CMD_GET_Q_CHANNEL = 0x20, /* . Y Y Y Y */
+ CMD_GET_SENSE_DATA = 0x30, /* . . . . . */
+ CMD_GET_STATUS = 0x40, /* . Y Y Y Y */
+ CMD_SET_MODE = 0x50, /* . Y Y Y Y */
+ CMD_SOFT_RESET = 0x60, /* . . . . . */
+ CMD_STOP_AUDIO = 0x70, /* . Y Y Y Y */
+ CMD_STOP_AUDIO_TIME = 0x80, /* . . . . . */
+ CMD_GET_VOLUME = 0x8e, /* . . . . . */
+ CMD_CONFIG_DRIVE = 0x90, /* . Y Y Y Y */
+ CMD_SET_DRIVE_MODE = 0xa0, /* . . . . . */
+ CMD_READ_UPC = 0xa2, /* . . . . . */
+ CMD_SET_VOLUME = 0xae, /* . . . . . */
+ CMD_READ_1 = 0xb0, /* . . . . . */
+ CMD_READ_PLAY = 0xc0, /* . Y Y Y Y */
+ CMD_READ_DOUBLE = 0xc1, /* N N N N Y */
+ CMD_GET_DRIVE_MODE = 0xc2, /* . Y Y Y Y */
+ CMD_READ = 0xc3, /* . . . . . */
+ CMD_SET_INTERLEAVE = 0xc8, /* . . . . . */
+ CMD_GET_VERSION = 0xdc, /* . . . . . */
+ CMD_STOP = 0xf0, /* . Y Y Y Y */
+ CMD_EJECT = 0xf6, /* N N N . . */
+ CMD_CLOSE_TRAY = 0xf8, /* N N N . . */
+ CMD_LOCK_DOOR = 0xfe, /* N N N . . */
+};
+
+/*
+ * The SET_MODE argument
+ */
+#define MODE_TESTMODE 0x80 /* DATALENGTH setting ignored */
+#define MODE_DATALENGTH 0x40 /* Read raw (2352 byte) sectors */
+#define MODE_ECCMODE 0x20 /* Do not use secondary ECC */
+#define MODE_SPINDOWN 0x08 /* Spindown */
+#define MODE_GET_TOC 0x04 /* Next Q channel read gets TOC */
+#define MODE_MUTEDATA 0x01 /* Do not playback data as audio */
+
+/*
+ * The CONFIG_DRIVE argument
+ */
+#define CONFIG_IRQFLAGS 0x10 /* Set IRQ flags */
+#define CONFIG_TIMEOUT 0x08 /* Set DMA timeout */
+#define CONFIG_UPCFLAG 0x04 /* Next command will be READ_UPC */
+#define CONFIG_DMAMODE 0x02 /* Set DMA mode */
+#define CONFIG_LENGTH 0x01 /* Set MSB/LSB of DMA block size */
+
+#define CONFIG_ERRIRQ 0x04 /* IRQ on error */
+#define CONFIG_POSTIRQ 0x02 /* IRQ on data transfered */
+#define CONFIG_PREIRQ 0x01 /* IRQ on data ready */
+
+/*
+ * The LOCK_DOOR argument
+ */
+enum {
+ DOOR_UNLOCK = 0,
+ DOOR_LOCK = 1,
+};
+
+/*
+ * The device registers
+ */
+enum {
+ RREG_DATA = 0,
+ RREG_STATUS = 1,
+
+ WREG_DATA = 0,
+ WREG_RESET = 1,
+ WREG_HW_CONFIG = 2,
+ WREG_CHANNEL = 3,
+};
+
+/*
+ * The status byte returned from every command; set if description is true
+ */
+#define STATUS_OPEN 0x80 /* Door is open */
+#define STATUS_DISKSET 0x40 /* Disk set (recognized) */
+#define STATUS_CHANGED 0x20 /* Disk was changed */
+#define STATUS_CHECK 0x10 /* Disk rotates, servo is on */
+#define STATUS_AUDIOTR 0x08 /* Current track is audio */
+#define STATUS_RDERR 0x04 /* Read error, refer SENSE KEY */
+#define STATUS_AUDIOBS 0x02 /* Currently playing audio */
+#define STATUS_CMDERR 0x01 /* Command, param or format error */
+
+/*
+ * The status byte available from RREG_STATUS; reset if description is true
+ */
+#define STATUS_DOOR 0x10 /* Door is open */
+#define STATUS_STEN 0x04 /* I/O base contains status */
+#define STATUS_DTEN 0x02 /* I/O base contains data */
+
+struct mitsumi_cdrom {
+ void __iomem *ioaddr;
+ struct mutex mutex;
+
+ int audiostatus;
+ int uptodate;
+ int media_changed;
+
+ struct completion *io_done;
+
+ struct cdrom_tochdr header;
+ struct cdrom_tocentry *toc;
+ struct cdrom_tocentry leadout;
+ struct cdrom_msf fragment;
+
+ struct gendisk *disk;
+ struct cdrom_device_info info;
+};
+
+static inline sector_t frame_to_sector(sector_t frame)
+{
+ return (CD_FRAMESIZE >> 9) * frame;
+}
+
+static inline sector_t sector_to_frame(sector_t sector)
+{
+ return (sector << 9) / CD_FRAMESIZE;
+}
+
+static void frame_to_msf(sector_t frame, struct cdrom_msf0 *msf)
+{
+ frame += CD_MSF_OFFSET;
+ msf->frame = frame % CD_FRAMES;
+ frame /= CD_FRAMES;
+ msf->second = frame % CD_SECS;
+ msf->minute = frame / CD_SECS;
+}
+
+static sector_t msf_to_frame(const struct cdrom_msf0 *msf)
+{
+ return (CD_SECS * msf->minute + msf->second) * CD_FRAMES +
+ msf->frame - CD_MSF_OFFSET;
+}
+
+/*
+ * LOCKING: mutex_lock(&mcd->mutex)
+ */
+static void __mitsumi_get_frame(struct mitsumi_cdrom *mcd, unsigned char *dst)
+{
+ ioread8_rep(mcd->ioaddr + RREG_DATA, dst, CD_FRAMESIZE);
+ /*
+ * Allow the drive some time to recover
+ */
+ udelay(100);
+}
+
+static void __mitsumi_write_cmd(struct mitsumi_cdrom *mcd, unsigned char cmd,
+ unsigned char *arg, size_t size)
+{
+ iowrite8(cmd, mcd->ioaddr + WREG_DATA);
+ while (size--)
+ iowrite8(*arg++, mcd->ioaddr + WREG_DATA);
+}
+
+static int mitsumi_get_value(struct mitsumi_cdrom *mcd, unsigned char *value,
+ unsigned long msecs)
+{
+ unsigned long timeout = jiffies + msecs_to_jiffies(msecs);
+ int err = 0;
+
+ while (ioread8(mcd->ioaddr + RREG_STATUS) & STATUS_STEN) {
+ if (time_after(jiffies, timeout)) {
+ err = -EIO;
+ goto out;
+ }
+ cond_resched();
+ }
+ *value = ioread8(mcd->ioaddr + RREG_DATA);
+ out:
+ return err;
+}
+
+static int mitsumi_write_cmd(struct mitsumi_cdrom *mcd, unsigned char cmd,
+ unsigned char *arg, size_t size,
+ unsigned long msecs)
+{
+ unsigned char status;
+ int err;
+
+ __mitsumi_write_cmd(mcd, cmd, arg, size);
+
+ err = mitsumi_get_value(mcd, &status, msecs);
+ if (err)
+ goto out;
+
+ if (status & STATUS_CMDERR) {
+ printk(KERN_ERR "mitsumi: command error: cmd=%02x, "
+ "status=%02x\n", cmd, status);
+ err = -EIO;
+ goto out;
+ }
+ if (status & STATUS_CHANGED) {
+ mcd->uptodate = 0;
+ mcd->media_changed = 1;
+ }
+ if (!(status & STATUS_AUDIOTR)) {
+ mcd->audiostatus = CDROM_AUDIO_INVALID;
+ goto out;
+ }
+ if (status & STATUS_AUDIOBS) {
+ mcd->audiostatus = CDROM_AUDIO_PLAY;
+ goto out;
+ }
+ if (mcd->audiostatus == CDROM_AUDIO_PLAY) {
+ mcd->audiostatus = CDROM_AUDIO_COMPLETED;
+ goto out;
+ }
+ if (mcd->audiostatus == CDROM_AUDIO_INVALID)
+ mcd->audiostatus = CDROM_AUDIO_NO_STATUS;
+ out:
+ return err;
+}
+
+static int mitsumi_read_cmd(struct mitsumi_cdrom *mcd, unsigned char cmd,
+ unsigned char *buf, size_t size,
+ unsigned long msecs)
+{
+ int err = mitsumi_write_cmd(mcd, cmd, NULL, 0, msecs);
+
+ while (!err && size--)
+ err = mitsumi_get_value(mcd, buf++, msecs);
+
+ return err;
+}
+
+static int mitsumi_read_subchnl(struct mitsumi_cdrom *mcd,
+ struct cdrom_subchnl *q)
+{
+ unsigned char buf[10];
+ int err;
+
+ err = mitsumi_read_cmd(mcd, CMD_GET_Q_CHANNEL, buf, sizeof buf, 2000);
+ if (err)
+ goto out;
+
+ q->cdsc_format = CDROM_MSF;
+ q->cdsc_audiostatus = mcd->audiostatus;
+
+ q->cdsc_adr = buf[0];
+ q->cdsc_ctrl = buf[0] >> 4;
+ q->cdsc_trk = BCD2BIN(buf[1]);
+ q->cdsc_ind = BCD2BIN(buf[2]);
+
+ q->cdsc_reladdr.msf.minute = BCD2BIN(buf[3]);
+ q->cdsc_reladdr.msf.second = BCD2BIN(buf[4]);
+ q->cdsc_reladdr.msf.frame = BCD2BIN(buf[5]);
+
+ q->cdsc_absaddr.msf.minute = BCD2BIN(buf[7]);
+ q->cdsc_absaddr.msf.second = BCD2BIN(buf[8]);
+ q->cdsc_absaddr.msf.frame = BCD2BIN(buf[9]);
+ out:
+ return err;
+}
+
+static int __mitsumi_read_toc(struct mitsumi_cdrom *mcd)
+{
+ int tracks = mcd->header.cdth_trk1 - mcd->header.cdth_trk0 + 1;
+ int tries, err;
+
+ kfree(mcd->toc);
+ mcd->toc = kzalloc(tracks * sizeof *mcd->toc, GFP_KERNEL);
+ if (!mcd->toc) {
+ err = -ENOMEM;
+ goto out;
+ }
+ for (tries = 300; tries; tries--) { /* why 300? */
+ struct cdrom_subchnl q;
+ int i;
+
+ err = mitsumi_read_subchnl(mcd, &q);
+ if (err)
+ goto out;
+
+ if (q.cdsc_trk != 0)
+ continue;
+
+ i = q.cdsc_ind;
+ if (i < mcd->header.cdth_trk0 || i > mcd->header.cdth_trk1)
+ continue;
+
+ i -= mcd->header.cdth_trk0;
+ if (mcd->toc[i].cdte_track != 0)
+ continue;
+
+ mcd->toc[i].cdte_track = q.cdsc_ind;
+ mcd->toc[i].cdte_adr = q.cdsc_adr;
+ mcd->toc[i].cdte_ctrl = q.cdsc_ctrl;
+ mcd->toc[i].cdte_format = q.cdsc_format;
+ mcd->toc[i].cdte_addr = q.cdsc_absaddr;
+
+ if (!--tracks)
+ goto out;
+ }
+ err = -EIO;
+ out:
+ return err;
+}
+
+static int mitsumi_set_mode(struct mitsumi_cdrom *mcd, unsigned char mode)
+{
+ mode |= MODE_MUTEDATA;
+
+ return mitsumi_write_cmd(mcd, CMD_SET_MODE, &mode, 1, 5000);
+}
+
+static int mitsumi_stop_audio(struct mitsumi_cdrom *mcd)
+{
+ return mitsumi_write_cmd(mcd, CMD_STOP_AUDIO, NULL, 0, 5000);
+}
+
+static int mitsumi_read_toc(struct mitsumi_cdrom *mcd)
+{
+ int err;
+
+ err = mitsumi_stop_audio(mcd);
+ if (err)
+ goto out;
+
+ err = mitsumi_set_mode(mcd, MODE_GET_TOC);
+ if (err)
+ goto out;
+
+ err = __mitsumi_read_toc(mcd);
+ if (err)
+ goto out;
+
+ err = mitsumi_set_mode(mcd, 0);
+ out:
+ return err;
+}
+
+static int mitsumi_read_header(struct mitsumi_cdrom *mcd)
+{
+ unsigned char buf[8];
+ int err;
+
+ err = mitsumi_read_cmd(mcd, CMD_GET_VOLUME_INFO, buf, sizeof buf, 2000);
+ if (err)
+ goto out;
+
+ mcd->header.cdth_trk0 = BCD2BIN(buf[0]);
+ mcd->header.cdth_trk1 = BCD2BIN(buf[1]);
+
+ if (mcd->header.cdth_trk1 < mcd->header.cdth_trk0) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ mcd->leadout.cdte_track = CDROM_LEADOUT;
+ mcd->leadout.cdte_format = CDROM_MSF;
+
+ mcd->leadout.cdte_addr.msf.minute = BCD2BIN(buf[2]);
+ mcd->leadout.cdte_addr.msf.second = BCD2BIN(buf[3]);
+ mcd->leadout.cdte_addr.msf.frame = BCD2BIN(buf[4]);
+
+ /*
+ * First sector MSF in 5-7
+ */
+ out:
+ return err;
+}
+
+static int mitsumi_config_drive(struct mitsumi_cdrom *mcd)
+{
+ unsigned char arg[2];
+ int err;
+
+ arg[0] = CONFIG_DMAMODE;
+ arg[1] = 0;
+
+ err = mitsumi_write_cmd(mcd, CMD_CONFIG_DRIVE, arg, sizeof arg, 1000);
+ if (err)
+ goto out;
+
+ arg[0] = CONFIG_IRQFLAGS;
+ arg[1] = CONFIG_PREIRQ;
+
+ err = mitsumi_write_cmd(mcd, CMD_CONFIG_DRIVE, arg, sizeof arg, 1000);
+ out:
+ return err;
+}
+
+static int mitsumi_update(struct mitsumi_cdrom *mcd)
+{
+ sector_t capacity = 0;
+ int err;
+
+ err = mitsumi_read_header(mcd);
+ if (err)
+ goto out;
+
+ err = mitsumi_read_toc(mcd);
+ if (err)
+ goto out;
+
+ err = mitsumi_config_drive(mcd);
+ if (err)
+ goto out;
+
+ capacity = frame_to_sector(msf_to_frame(&mcd->leadout.cdte_addr.msf));
+ out:
+ set_capacity(mcd->disk, capacity);
+ return err;
+}
+
+static int mitsumi_open(struct cdrom_device_info *cdi, int purpose)
+{
+ /*
+ * Uniform CD-ROM driver calls into audio_ioctl first even for data
+ * (cdrom_count_tracks) so we're good to go
+ */
+ return 0;
+}
+
+static void mitsumi_release(struct cdrom_device_info *cdi)
+{
+}
+
+static int mitsumi_get_status(struct mitsumi_cdrom *mcd)
+{
+ return mitsumi_write_cmd(mcd, CMD_GET_STATUS, NULL, 0, 5000);
+}
+
+static int mitsumi_media_changed(struct cdrom_device_info *cdi, int disc_nr)
+{
+ struct mitsumi_cdrom *mcd = cdi->handle;
+ int ret;
+
+ mutex_lock(&mcd->mutex);
+ ret = mcd->media_changed;
+
+ if (!ret && !mitsumi_get_status(mcd))
+ ret = mcd->media_changed;
+
+ mcd->media_changed = 0;
+ mutex_unlock(&mcd->mutex);
+ return ret;
+}
+
+static int mitsumi_read_tochdr(struct mitsumi_cdrom *mcd,
+ struct cdrom_tochdr *header)
+{
+ *header = mcd->header;
+ return 0;
+}
+
+static int mitsumi_read_tocentry(struct mitsumi_cdrom *mcd,
+ struct cdrom_tocentry *entry)
+{
+ int err = 0;
+
+ if (entry->cdte_track == CDROM_LEADOUT) {
+ *entry = mcd->leadout;
+ goto out;
+ }
+ if (entry->cdte_track < mcd->header.cdth_trk0 ||
+ entry->cdte_track > mcd->header.cdth_trk1) {
+ err = -EINVAL;
+ goto out;
+ }
+ *entry = mcd->toc[entry->cdte_track - mcd->header.cdth_trk0];
+ out:
+ return err;
+}
+
+static int mitsumi_start(struct mitsumi_cdrom *mcd)
+{
+ /*
+ * Drive spins up automatically only
+ */
+ return 0;
+}
+
+static int mitsumi_stop(struct mitsumi_cdrom *mcd)
+{
+ return mitsumi_write_cmd(mcd, CMD_STOP, NULL, 0, 2000);
+}
+
+static int mitsumi_pause(struct mitsumi_cdrom *mcd)
+{
+ struct cdrom_subchnl q;
+ int err;
+
+ if (mcd->audiostatus != CDROM_AUDIO_PLAY) {
+ err = -EINVAL;
+ goto out;
+ }
+ err = mitsumi_stop_audio(mcd);
+ if (err)
+ goto out;
+
+ err = mitsumi_read_subchnl(mcd, &q);
+ if (err)
+ goto out;
+
+ mcd->fragment.cdmsf_min0 = q.cdsc_absaddr.msf.minute;
+ mcd->fragment.cdmsf_sec0 = q.cdsc_absaddr.msf.second;
+ mcd->fragment.cdmsf_frame0 = q.cdsc_absaddr.msf.frame;
+
+ mcd->audiostatus = CDROM_AUDIO_PAUSED;
+ out:
+ return err;
+}
+
+static int mitsumi_play(struct mitsumi_cdrom *mcd)
+{
+ unsigned char arg[6];
+
+ arg[0] = BIN2BCD(mcd->fragment.cdmsf_min0);
+ arg[1] = BIN2BCD(mcd->fragment.cdmsf_sec0);
+ arg[2] = BIN2BCD(mcd->fragment.cdmsf_frame0);
+ arg[3] = BIN2BCD(mcd->fragment.cdmsf_min1);
+ arg[4] = BIN2BCD(mcd->fragment.cdmsf_sec1);
+ arg[5] = BIN2BCD(mcd->fragment.cdmsf_frame1);
+
+ return mitsumi_write_cmd(mcd, CMD_READ_PLAY, arg, sizeof arg, 5000);
+}
+
+static int mitsumi_resume(struct mitsumi_cdrom *mcd)
+{
+ int err;
+
+ if (mcd->audiostatus != CDROM_AUDIO_PAUSED) {
+ err = -EINVAL;
+ goto out;
+ }
+ err = mitsumi_play(mcd);
+ out:
+ return err;
+}
+
+static int mitsumi_play_msf(struct mitsumi_cdrom *mcd, struct cdrom_msf *msf)
+{
+ mcd->fragment = *msf;
+
+ return mitsumi_play(mcd);
+}
+
+static int mitsumi_play_trkind(struct mitsumi_cdrom *mcd, struct cdrom_ti *ti)
+{
+ struct cdrom_tocentry *entry;
+ struct cdrom_msf0 msf;
+ int err;
+
+ if (ti->cdti_trk0 < mcd->header.cdth_trk0 ||
+ ti->cdti_trk1 < ti->cdti_trk0 ||
+ ti->cdti_trk1 > mcd->header.cdth_trk1) {
+ err = -EINVAL;
+ goto out;
+ }
+ entry = &mcd->toc[ti->cdti_trk0 - mcd->header.cdth_trk0];
+
+ mcd->fragment.cdmsf_min0 = entry->cdte_addr.msf.minute;
+ mcd->fragment.cdmsf_sec0 = entry->cdte_addr.msf.second;
+ mcd->fragment.cdmsf_frame0 = entry->cdte_addr.msf.frame;
+
+ if (ti->cdti_trk1 < mcd->header.cdth_trk1)
+ entry = &mcd->toc[ti->cdti_trk1 - mcd->header.cdth_trk0 + 1];
+ else
+ entry = &mcd->leadout;
+
+ frame_to_msf(msf_to_frame(&entry->cdte_addr.msf) - 1, &msf);
+
+ mcd->fragment.cdmsf_min1 = msf.minute;
+ mcd->fragment.cdmsf_sec1 = msf.second;
+ mcd->fragment.cdmsf_frame1 = msf.frame;
+
+ err = mitsumi_play(mcd);
+ out:
+ return err;
+}
+
+static int mitsumi_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
+ void *arg)
+{
+ struct mitsumi_cdrom *mcd = cdi->handle;
+ int err;
+
+ mutex_lock(&mcd->mutex);
+ if (mcd->uptodate) {
+ err = mitsumi_get_status(mcd);
+ if (err)
+ goto out;
+ }
+ if (!mcd->uptodate) {
+ err = mitsumi_update(mcd);
+ if (err)
+ goto out;
+
+ mcd->uptodate = 1;
+ }
+ switch (cmd) {
+ case CDROMSUBCHNL:
+ err = mitsumi_read_subchnl(mcd, arg);
+ break;
+ case CDROMREADTOCHDR:
+ err = mitsumi_read_tochdr(mcd, arg);
+ break;
+ case CDROMREADTOCENTRY:
+ err = mitsumi_read_tocentry(mcd, arg);
+ break;
+ case CDROMSTART:
+ err = mitsumi_start(mcd);
+ break;
+ case CDROMSTOP:
+ err = mitsumi_stop(mcd);
+ break;
+ case CDROMPAUSE:
+ err = mitsumi_pause(mcd);
+ break;
+ case CDROMRESUME:
+ err = mitsumi_resume(mcd);
+ break;
+ case CDROMPLAYMSF:
+ err = mitsumi_play_msf(mcd, arg);
+ break;
+ case CDROMPLAYTRKIND:
+ err = mitsumi_play_trkind(mcd, arg);
+ break;
+ default:
+ err = -ENOSYS;
+ break;
+ }
+ out:
+ mutex_unlock(&mcd->mutex);
+ return err;
+}
+
+static struct cdrom_device_ops mitsumi_dops = {
+ .open = mitsumi_open,
+ .release = mitsumi_release,
+ .media_changed = mitsumi_media_changed,
+ .audio_ioctl = mitsumi_audio_ioctl,
+ .capability = CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO
+};
+
+static irqreturn_t mitsumi_intr(int irq, void *dev_id)
+{
+ struct mitsumi_cdrom *mcd = dev_id;
+ unsigned char status;
+
+ status = ioread8(mcd->ioaddr + RREG_STATUS);
+ if (status & STATUS_DTEN) {
+ /*
+ * Requested data is not ready
+ */
+ if (status & STATUS_STEN)
+ printk(KERN_INFO
+ "mitsumi: ambiguous interrupt (status %#x)\n",
+ status);
+ else
+ printk(KERN_INFO "mitsumi: interrupt (status %#x)\n",
+ ioread8(mcd->ioaddr + RREG_DATA));
+ } else {
+ struct completion *io_done = mcd->io_done;
+
+ if (io_done) {
+ mcd->io_done = NULL;
+ complete(io_done);
+ }
+ }
+ return IRQ_HANDLED;
+}
+
+static int mitsumi_get_frame(struct mitsumi_cdrom *mcd, sector_t frame,
+ unsigned char *dst)
+{
+ struct completion io_wait;
+ struct cdrom_msf0 msf;
+ unsigned char arg[6];
+ int err = 0;
+
+ init_completion(&io_wait);
+ frame_to_msf(frame, &msf);
+
+ arg[0] = BIN2BCD(msf.minute);
+ arg[1] = BIN2BCD(msf.second);
+ arg[2] = BIN2BCD(msf.frame);
+ arg[3] = 0;
+ arg[4] = 0;
+ arg[5] = 1;
+
+ mutex_lock(&mcd->mutex);
+ mcd->io_done = &io_wait;
+ __mitsumi_write_cmd(mcd, CMD_READ_PLAY, arg, sizeof arg);
+ /*
+ * Wait for the interrupt handler to notify us when the I/O completes
+ */
+ if (!wait_for_completion_timeout(&io_wait, msecs_to_jiffies(5000))) {
+ printk(KERN_ERR "mitsumi: I/O wait timed out\n");
+ err = -EIO;
+ goto out;
+
+ }
+ __mitsumi_get_frame(mcd, dst);
+ out:
+ mutex_unlock(&mcd->mutex);
+ return err;
+}
+
+static unsigned int mitsumi_read(struct mitsumi_cdrom *mcd, struct bio *bio)
+{
+ sector_t frame = sector_to_frame(bio->bi_sector);
+ unsigned int bytes = 0;
+ struct bio_vec *bvec;
+ int segno;
+
+ bio_for_each_segment(bvec, bio, segno) {
+ unsigned char *dst;
+ unsigned int len;
+
+ dst = page_address(bvec->bv_page) + bvec->bv_offset;
+ for (len = bvec->bv_len; len; len -= CD_FRAMESIZE) {
+ if (mitsumi_get_frame(mcd, frame++, dst))
+ goto out;
+
+ bytes += CD_FRAMESIZE;
+ dst += CD_FRAMESIZE;
+ }
+ }
+ out:
+ return bytes;
+}
+
+static void mitsumi_request(struct request_queue *q)
+{
+ struct request *req;
+
+ while ((req = elv_next_request(q))) {
+ struct bio *bio;
+ int sectors = 0;
+
+ if (!blk_fs_request(req)) {
+ end_request(req, 0);
+ continue;
+ }
+ if (rq_data_dir(req) != READ) {
+ printk(KERN_WARNING
+ "mitsumi: non-read request to CD\n");
+ end_request(req, 0);
+ continue;
+ }
+ spin_unlock_irq(q->queue_lock);
+ rq_for_each_bio(bio, req) {
+ unsigned int bytes;
+
+ bytes = mitsumi_read(req->rq_disk->private_data, bio);
+ sectors += bytes >> 9;
+
+ if (bytes != bio->bi_size)
+ break;
+ }
+ spin_lock_irq(q->queue_lock);
+ if (!sectors || end_that_request_first(req, 1, sectors)) {
+ end_request(req, 0);
+ continue;
+ }
+ blkdev_dequeue_request(req);
+ end_that_request_last(req, 1);
+ }
+}
+
+static int mitsumi_block_open(struct inode *inode, struct file *file)
+{
+ struct mitsumi_cdrom *mcd = inode->i_bdev->bd_disk->private_data;
+
+ return cdrom_open(&mcd->info, inode, file);
+}
+
+static int mitsumi_block_release(struct inode *inode, struct file *file)
+{
+ struct mitsumi_cdrom *mcd = inode->i_bdev->bd_disk->private_data;
+
+ return cdrom_release(&mcd->info, file);
+}
+
+static int mitsumi_block_ioctl(struct inode *inode, struct file *file,
+ unsigned cmd, unsigned long arg)
+{
+ struct mitsumi_cdrom *mcd = inode->i_bdev->bd_disk->private_data;
+
+ return cdrom_ioctl(file, &mcd->info, inode, cmd, arg);
+}
+
+static int mitsumi_block_media_changed(struct gendisk *disk)
+{
+ struct mitsumi_cdrom *mcd = disk->private_data;
+
+ return cdrom_media_changed(&mcd->info);
+}
+
+static struct block_device_operations mitsumi_bdops = {
+ .owner = THIS_MODULE,
+ .open = mitsumi_block_open,
+ .release = mitsumi_block_release,
+ .ioctl = mitsumi_block_ioctl,
+ .media_changed = mitsumi_block_media_changed,
+};
+
+static int mitsumi_read_version(struct mitsumi_cdrom *mcd, unsigned char *ver,
+ unsigned char *rev)
+{
+ unsigned char buf[2];
+ int err;
+
+ err = mitsumi_read_cmd(mcd, CMD_GET_VERSION, buf, sizeof buf, 2000);
+ if (err)
+ goto out;
+
+ *ver = buf[0];
+ *rev = buf[1];
+ out:
+ return err;
+}
+
+static void mitsumi_reset(struct mitsumi_cdrom *mcd)
+{
+ iowrite8(0, mcd->ioaddr + WREG_CHANNEL); /* no dma, no irq */
+ iowrite8(0, mcd->ioaddr + WREG_RESET); /* hardware reset */
+
+ /*
+ * Nothing to poll, no interrupt, ...
+ */
+ msleep(500);
+}
+
+static int __devinit mitsumi_match(struct device *dev, unsigned int id)
+{
+ int match = port[id] != 0 && irq[id] != 0;
+
+ if (!match)
+ printk(KERN_ERR "mitsumi: please specify port and irq\n");
+
+ return match;
+}
+
+static int __devinit mitsumi_probe(struct device *dev, unsigned int id)
+{
+ struct mitsumi_cdrom *mcd;
+ unsigned char ver;
+ unsigned char rev;
+ char *model;
+ struct gendisk *disk;
+ int err;
+
+ mcd = kzalloc(sizeof *mcd, GFP_KERNEL);
+ if (!mcd) {
+ err = -ENOMEM;
+ goto out;
+ }
+ if (!request_region(port[id], 4, "mitsumi")) {
+ err = -EBUSY;
+ goto out_free;;
+ }
+ mcd->ioaddr = ioport_map(port[id], 4);
+
+ mitsumi_reset(mcd);
+
+ mutex_init(&mcd->mutex);
+ mcd->audiostatus = CDROM_AUDIO_INVALID;
+
+ err = mitsumi_read_version(mcd, &ver, &rev);
+ if (err)
+ goto out_release_region;
+
+ switch (ver) {
+ case 'M':
+ model = rev <= 2 ? "LU002S" : rev <= 5 ? "LU005S" : "LU006S";
+ break;
+ case 'F':
+ model = "FX001";
+ break;
+
+ case 'D':
+ model = "FX001D";
+ break;
+ default:
+ printk(KERN_WARNING "mitsumi: unknown firmware %c%d, driver "
+ "not initialized\n", ver, rev);
+ goto out_release_region;
+ };
+
+ err = request_irq(irq[id], mitsumi_intr, IRQF_DISABLED, "mitsumi", mcd);
+ if (err)
+ goto out_release_region;
+
+ disk = alloc_disk(1);
+ if (!disk) {
+ err = -ENOMEM;
+ goto out_free_irq;
+ }
+ mcd->disk = disk;
+ disk->private_data = mcd;
+
+ disk->major = MITSUMI_CDROM_MAJOR;
+ disk->first_minor = id;
+ disk->fops = &mitsumi_bdops;
+ disk->flags = GENHD_FL_CD;
+ sprintf(disk->disk_name, "mitsumi%u", id);
+
+ disk->queue = blk_init_queue(mitsumi_request, NULL);
+ if (!disk->queue) {
+ err = -ENOMEM;
+ goto out_put_disk;
+ }
+ blk_queue_hardsect_size(disk->queue, CD_FRAMESIZE);
+
+ mcd->info.ops = &mitsumi_dops;
+ mcd->info.speed = 1;
+ mcd->info.capacity = 1;
+ mcd->info.handle = mcd;
+ strcpy(mcd->info.name, disk->disk_name);
+
+ err = register_cdrom(&mcd->info);
+ if (err)
+ goto out_cleanup_queue;
+
+ printk(KERN_INFO "mitsumi: found %s drive (firmware %c%d) at %#lx, "
+ "irq %d\n", model, ver, rev, port[id], irq[id]);
+
+ add_disk(disk);
+ dev_set_drvdata(dev, mcd);
+ return 0;
+
+ out_cleanup_queue:
+ blk_cleanup_queue(disk->queue);
+ out_put_disk:
+ put_disk(disk);
+ out_free_irq:
+ free_irq(irq[id], mcd);
+ out_release_region:
+ ioport_unmap(mcd->ioaddr);
+ release_region(port[id], 4);
+ out_free:
+ kfree(mcd);
+ out:
+ return err;
+}
+
+static int __devexit mitsumi_remove(struct device *dev, unsigned int id)
+{
+ struct mitsumi_cdrom *mcd = dev_get_drvdata(dev);
+
+ dev_set_drvdata(dev, NULL);
+ del_gendisk(mcd->disk);
+ unregister_cdrom(&mcd->info);
+ blk_cleanup_queue(mcd->disk->queue);
+ put_disk(mcd->disk);
+ free_irq(irq[id], mcd);
+ ioport_unmap(mcd->ioaddr);
+ release_region(port[id], 4);
+ kfree(mcd->toc);
+ kfree(mcd);
+ return 0;
+}
+
+static struct isa_driver mitsumi_driver = {
+ .match = mitsumi_match,
+ .probe = mitsumi_probe,
+ .remove = __devexit_p(mitsumi_remove),
+
+ .driver = {
+ .name = "mitsumi"
+ }
+};
+
+static int __init mitsumi_init(void)
+{
+ int err;
+
+ err = register_blkdev(MITSUMI_CDROM_MAJOR, "mitsumi");
+ if (err)
+ goto out;
+
+ err = isa_register_driver(&mitsumi_driver, NR_DRIVES);
+ if (err)
+ unregister_blkdev(MITSUMI_CDROM_MAJOR, "mitsumi");
+ out:
+ return err;
+}
+
+static void __exit mitsumi_exit(void)
+{
+ isa_unregister_driver(&mitsumi_driver);
+ unregister_blkdev(MITSUMI_CDROM_MAJOR, "mitsumi");
+}
+
+module_init(mitsumi_init);
+module_exit(mitsumi_exit);
On 06/04/2007 11:42 AM, Rene Herman wrote:
[ ... ]
> Unfortunately, I can make the box oops by just doing enough of those dd
> runs in a row (this one with bs=2k count=128, oopsed the seventh time or
> something):
>
> ===
> BUG: unable to handle kernel paging request at virtual address 8c1d2071
> printing eip:
> c10a6d6f
> *pde = 00000000
> Oops: 0002 [#1]
> Modules linked in: mitsumi nfsd exportfs lockd sunrpc nls_cp437 msdos
> fat nls_base
> CPU: 0
> EIP: 0060:[<c10a6d6f>] Not tainted VLI
> EFLAGS: 00010246 (2.6.21.3 #1)
> EIP is at ioread8_rep+0x20/0x31
> eax: 00010000 ebx: 00010300 ecx: 00000800 edx: 00000300
> esi: c3145b30 edi: 8c1d2071 ebp: 8c1d2071 esp: c3145aec
> ds: 007b es: 007b fs: 00d8 gs: 0033 ss: 0068
> Process dd (pid: 1770, ti=c3145000 task=c3114110 task.ti=c3145000)
> Stack: 00000000 c3a7ad48 c486504d c4865ab7 00000006 50020034 c1015f7b
> 00000292
> 00000000 00520300 00000100 0007e000 00000000 c3340300 c10a0531
> 00000000
> c12adf60 00000000 00000001 00000000 00000000 00000000 dead4ead
> ffffffff
> Call Trace:
> [<c486504d>] __mitsumi_get_frame+0xc/0x16 [mitsumi]
> [<c4865ab7>] mitsumi_get_frame+0x120/0x134 [mitsumi]
> [<c1015f7b>] lock_timer_base+0x15/0x2f
> [<c10a0531>] cfq_set_request+0x0/0x144
Perhaps interesting (and perhaps not) -- I've been unable to reproduce the OOPS
after rebooting with elevator=as.
Rene.
On 06/04/2007 05:07 PM, Rene Herman wrote:
>> Call Trace:
>> [<c486504d>] __mitsumi_get_frame+0xc/0x16 [mitsumi]
>> [<c4865ab7>] mitsumi_get_frame+0x120/0x134 [mitsumi]
>> [<c1015f7b>] lock_timer_base+0x15/0x2f
>> [<c10a0531>] cfq_set_request+0x0/0x144
>
> Perhaps interesting (and perhaps not) -- I've been unable to reproduce
> the OOPS after rebooting with elevator=as.
Kernel is vanilla 2.6.21.3.
Rene.
Hi Rene,
On 6/4/07, Rene Herman <[email protected]> wrote:
> BUG: unable to handle kernel paging request at virtual address 8c1d2071
> printing eip:
> c10a6d6f
> *pde = 00000000
> Oops: 0002 [#1]
> Modules linked in: mitsumi nfsd exportfs lockd sunrpc nls_cp437 msdos
> fat nls_base
> CPU: 0
> EIP: 0060:[<c10a6d6f>] Not tainted VLI
> EFLAGS: 00010246 (2.6.21.3 #1)
> EIP is at ioread8_rep+0x20/0x31
[snip]
On 6/4/07, Rene Herman <[email protected]> wrote:
> Code: 00 00 89 c8 ef c3 0f c9 89 0a c3 57 3d ff ff 03 00 53 89 d7 89 c3
> 89 ca 77 15 66 31 c0 3d 00 00 01 00 74 04 0f 0b eb fe 0f b7 d3 <f3> 6c
> eb 0a 4a 78 07 8a 03 88 07 47 eb f6 5b 5f c3 57 3d ff ff
> EIP: [<c10a6d6f>] ioread8_rep+0x20/0x31 SS:ESP 0068:c3145aec
So this is the repz/insb instruction (f3 6c) in ioread8_rep() which it
reads ECX bytes from port EDX and stores the data in ES:[EDI].
Looking at the registers and stack:
On 6/4/07, Rene Herman <[email protected]> wrote:
> eax: 00010000 ebx: 00010300 ecx: 00000800 edx: 00000300
> esi: c3145b30 edi: 8c1d2071 ebp: 8c1d2071 esp: c3145aec
> ds: 007b es: 007b fs: 00d8 gs: 0033 ss: 0068
> Process dd (pid: 1770, ti=c3145000 task=c3114110 task.ti=c3145000)
> Stack: 00000000 c3a7ad48 c486504d c4865ab7 00000006 50020034 c1015f7b
> 00000292
> 00000000 00520300 00000100 0007e000 00000000 c3340300 c10a0531
> 00000000
> c12adf60 00000000 00000001 00000000 00000000 00000000 dead4ead
> ffffffff
We can see that we're reading 2048 bytes from port 0x300 and storing
the data in memory location 0x8c1d2071 which causes the OOPS. What's
surprising is that EBP is set to 0x8c1d2071 too which suggests stack
corruption (note that ioread8_rep() is a fastcall so it does not
create a stack frame of its own). What you could do here is add some
printks and watch how dst changes over time to see if you can figure
out a pattern.
Also, assuming CFQ fiddles with the request after we've done
elv_next_request() and dropped the lock, one thing worth trying is to
do blk_stop_queue() before we drop it and blk_start_queue after we
reacquire it so that we don't actually get any new I/O while we wait
for mitsumi_get_frame() to finish.
Pekka
On 06/04/2007 08:41 PM, Pekka Enberg wrote:
[ Jens' email address updated to his oracle address ]
> We can see that we're reading 2048 bytes from port 0x300 and storing
> the data in memory location 0x8c1d2071 which causes the OOPS. What's
> surprising is that EBP is set to 0x8c1d2071 too which suggests stack
> corruption (note that ioread8_rep() is a fastcall so it does not
> create a stack frame of its own). What you could do here is add some
> printks and watch how dst changes over time to see if you can figure
> out a pattern.
Mmm, I do always run with 4K stacks, I guess I'll try that next. I did follow
things a bit with printk. The normal and expected scenario is an N-frame request
consisting of N bio's, each consisting of 1 segment, each consisting of 1 frame.
That is, with this as mitsumi_read:
static unsigned int mitsumi_read(struct mitsumi_cdrom *mcd, struct bio *bio)
{
sector_t frame = sector_to_frame(bio->bi_sector);
unsigned int bytes = 0;
struct bio_vec *bvec;
int segno;
printk("%s: enter\n", __func__);
bio_for_each_segment(bvec, bio, segno) {
unsigned char *dst;
unsigned int len;
dst = page_address(bvec->bv_page) + bvec->bv_offset;
printk("%s: dst = %p, len = %#x\n", __func__, dst,
bvec->bv_len);
for (len = bvec->bv_len; len; len -= CD_FRAMESIZE) {
if (mitsumi_get_frame(mcd, frame++, dst))
goto out;
bytes += CD_FRAMESIZE;
dst += CD_FRAMESIZE;
}
}
out:
return bytes;
}
I get a long uninterrupted string of:
[ 903.130588] mitsumi_read: enter
[ 903.130630] mitsumi_read: dst = c2cd1000, len = 0x800
[ 903.143644] mitsumi_read: enter
[ 903.143686] mitsumi_read: dst = c2cd1800, len = 0x800
[ 903.156949] mitsumi_read: enter
[ 903.156992] mitsumi_read: dst = c3353000, len = 0x800
[ 903.170325] mitsumi_read: enter
[ 903.170367] mitsumi_read: dst = c3353800, len = 0x800
until it oopses:
[ 903.184750] mitsumi_read: enter
[ 903.184795] mitsumi_read: dst = c3a7f000, len = 0x800
[ 903.299315] mitsumi_read: dst = 8c1d2071, len = 0xc1033bda
[ 903.311457] BUG: unable to handle kernel paging request at virtual address
8c1d2071
And yes, it's the ioread8_rep that's trying to address the wrong dst. This
particular OOPS by the way while very similar doesn't have cfq in the backtrace
so here it is complete again:
===
BUG: unable to handle kernel paging request at virtual address 8c1d2071
printing eip:
c10a6d6f
*pde = 00000000
Oops: 0002 [#1]
Modules linked in: mitsumi nfsd exportfs lockd sunrpc nls_cp437 msdos fat nls_base
CPU: 0
EIP: 0060:[<c10a6d6f>] Not tainted VLI
EFLAGS: 00010246 (2.6.21.3 #1)
EIP is at ioread8_rep+0x20/0x31
eax: 00010000 ebx: 00010300 ecx: 00000800 edx: 00000300
esi: c2e26b20 edi: 8c1d2071 ebp: 8c1d2071 esp: c2e26adc
ds: 007b es: 007b fs: 00d8 gs: 0033 ss: 0068
Process dd (pid: 1437, ti=c2e26000 task=c1632050 task.ti=c2e26000)
Stack: 00000000 c3c55098 c486504d c4865ab7 00000006 50e20034 c11a5edc 00000034
00000000 00520300 50d50100 11d73140 00000034 00340300 5b3e343c 30392020
39322e33 00000000 00000001 00000000 00000000 00000000 dead4ead ffffffff
Call Trace:
[<c486504d>] __mitsumi_get_frame+0xc/0x16 [mitsumi]
[<c4865ab7>] mitsumi_get_frame+0x120/0x134 [mitsumi]
[<c1033bda>] mempool_free+0x5f/0x64
[<c4865b66>] mitsumi_read+0x9b/0xce [mitsumi]
[<c1033bda>] mempool_free+0x5f/0x64
[<c4865be2>] mitsumi_request+0x49/0xb5 [mitsumi]
[<c1099aae>] blk_start_queueing+0x14/0x1c
[<c10971c2>] elv_insert+0xa3/0x13f
[<c114fbc5>] _spin_lock_irq+0x2f/0x3a
[<c109a577>] __make_request+0x29f/0x2d3
[<c109a75b>] generic_make_request+0x136/0x146
[<c1048433>] kmem_cache_alloc+0x93/0x9e
[<c1033ae0>] mempool_alloc+0x32/0xcd
[<c1033ae0>] mempool_alloc+0x32/0xcd
[<c109a80f>] submit_bio+0xa4/0xaa
[<c106736b>] bio_alloc_bioset+0xb2/0x112
[<c1066dd1>] submit_bh+0xc2/0xdb
[<c1065fc4>] block_read_full_page+0x245/0x252
[<c1068346>] blkdev_get_block+0x0/0x36
[<c114ffff>] _write_unlock_irq+0x20/0x23
[<c103134f>] add_to_page_cache+0x71/0x78
[<c10368f3>] read_pages+0x7c/0xc1
[<c114ff7e>] _read_unlock_irq+0x20/0x23
[<c114ff7e>] _read_unlock_irq+0x20/0x23
[<c1025de0>] trace_hardirqs_on+0x11b/0x13e
[<c1036a25>] __do_page_cache_readahead+0xed/0x107
[<c1036b43>] blockable_page_cache_readahead+0x4d/0x9d
[<c1036c17>] make_ahead_window+0x84/0xa5
[<c1036d74>] page_cache_readahead+0x13c/0x15b
[<c1031cbc>] file_read_actor+0x7f/0x102
[<c1031953>] do_generic_mapping_read+0x110/0x3fa
[<c1031ec6>] generic_file_aio_read+0x187/0x1b0
[<c1031c3d>] file_read_actor+0x0/0x102
[<c104abc3>] do_sync_read+0xbf/0xfc
[<c101f2b8>] autoremove_wake_function+0x0/0x33
[<c1070fe1>] dnotify_parent+0x1b/0x66
[<c104aec2>] vfs_write+0xc9/0xff
[<c1027210>] __lock_release+0x2d/0x3f
[<c104ac87>] vfs_read+0x87/0xfd
[<c104af39>] sys_read+0x41/0x67
[<c1002490>] syscall_call+0x7/0xb
=======================
Code: 00 00 89 c8 ef c3 0f c9 89 0a c3 57 3d ff ff 03 00 53 89 d7 89 c3 89 ca 77
15 66 31 c0 3d 00 00 01 00 74 04 0f 0b eb fe 0f b7 d3 <f3> 6c eb 0a 4a 78 07 8a
03 88 07 47 eb f6 5b 5f c3 57 3d ff ff
EIP: [<c10a6d6f>] ioread8_rep+0x20/0x31 SS:ESP 0068:c2e26adc
===
> Also, assuming CFQ fiddles with the request after we've done
> elv_next_request() and dropped the lock, one thing worth trying is to
> do blk_stop_queue() before we drop it and blk_start_queue after we
> reacquire it so that we don't actually get any new I/O while we wait
> for mitsumi_get_frame() to finish.
That sounded like it might work (even if it might not be a proper solution) so I
added:
block_stop_queue(q);
immediately before the spin_unlock_irq(q->queue_lock) and a
block_start_queue(q);
immediately after the spin_lock_irq(q->queue_lock) in mitsumi_request. This
seems to be an immediate deadlock of sorts though. Box dead. :-\
Rene.
On 06/04/2007 10:38 PM, Rene Herman wrote:
> On 06/04/2007 08:41 PM, Pekka Enberg wrote:
>
> [ Jens' email address updated to his oracle address ]
>
>> We can see that we're reading 2048 bytes from port 0x300 and storing
>> the data in memory location 0x8c1d2071 which causes the OOPS. What's
>> surprising is that EBP is set to 0x8c1d2071 too which suggests stack
>> corruption (note that ioread8_rep() is a fastcall so it does not
>> create a stack frame of its own). What you could do here is add some
>> printks and watch how dst changes over time to see if you can figure
>> out a pattern.
>
> Mmm, I do always run with 4K stacks, I guess I'll try that next.
Nope, still there with 8K stacks and not harder to trigger.
Rene.