summaryrefslogtreecommitdiffstats
path: root/drivers/block/ide.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1997-04-29 21:13:14 +0000
committer <ralf@linux-mips.org>1997-04-29 21:13:14 +0000
commit19c9bba94152148523ba0f7ef7cffe3d45656b11 (patch)
tree40b1cb534496a7f1ca0f5c314a523c69f1fee464 /drivers/block/ide.c
parent7206675c40394c78a90e74812bbdbf8cf3cca1be (diff)
Import of Linux/MIPS 2.1.36
Diffstat (limited to 'drivers/block/ide.c')
-rw-r--r--drivers/block/ide.c496
1 files changed, 331 insertions, 165 deletions
diff --git a/drivers/block/ide.c b/drivers/block/ide.c
index d5193c2ee..ca9456479 100644
--- a/drivers/block/ide.c
+++ b/drivers/block/ide.c
@@ -1,7 +1,7 @@
/*
- * linux/drivers/block/ide.c Version 5.60 Nov 5, 1996
+ * linux/drivers/block/ide.c Version 6.02 Mar 11, 1997
*
- * Copyright (C) 1994-1996 Linus Torvalds & authors (see below)
+ * Copyright (C) 1994-1997 Linus Torvalds & authors (see below)
*/
#define _IDE_C /* needed by <linux/blk.h> */
@@ -269,6 +269,17 @@
* add m68k code from Geert Uytterhoeven
* probe all interfaces by default
* add ioctl to (re)probe an interface
+ * Version 6.00 use per device request queues
+ * attempt to optimize shared hwgroup performance
+ * add ioctl to manually adjust bandwidth algorithms
+ * add kerneld support for the probe module
+ * fix bug in ide_error()
+ * fix bug in the first ide_get_lock() call for Atari
+ * don't flush leftover data for ATAPI devices
+ * Version 6.01 clear hwgroup->active while the hwgroup sleeps
+ * support HDIO_GETGEO for floppies
+ * Version 6.02 fix ide_ack_intr() call
+ * check partition table on floppies
*
* Some additional driver compile-time options are in ide.h
*
@@ -294,6 +305,8 @@
#include <linux/hdreg.h>
#include <linux/genhd.h>
#include <linux/malloc.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
#include <asm/byteorder.h>
#include <asm/irq.h>
@@ -301,11 +314,6 @@
#include <asm/io.h>
#include <asm/bitops.h>
-#ifdef CONFIG_PCI
-#include <linux/bios32.h>
-#include <linux/pci.h>
-#endif /* CONFIG_PCI */
-
#include "ide.h"
#include "ide_modes.h"
@@ -354,18 +362,14 @@ static unsigned long read_timer(void)
restore_flags(flags);
return (t - i);
}
+#endif /* DISK_RECOVERY_TIME */
-static void set_recovery_timer (ide_hwif_t *hwif)
+static inline void set_recovery_timer (ide_hwif_t *hwif)
{
+#if (DISK_RECOVERY_TIME > 0)
hwif->last_time = read_timer();
-}
-#define SET_RECOVERY_TIMER(drive) set_recovery_timer (drive)
-
-#else
-
-#define SET_RECOVERY_TIMER(drive)
-
#endif /* DISK_RECOVERY_TIME */
+}
/*
* Do not even *think* about calling this!
@@ -630,7 +634,8 @@ void ide_geninit (struct gendisk *gd)
ide_drive_t *drive = &hwif->drives[unit];
drive->part[0].nr_sects = current_capacity(drive);
- if (!drive->present || drive->media != ide_disk || drive->driver == NULL)
+ if (!drive->present || (drive->media != ide_disk && drive->media != ide_floppy) ||
+ drive->driver == NULL || !drive->part[0].nr_sects)
drive->part[0].start_sect = -1; /* skip partition check */
}
}
@@ -720,10 +725,8 @@ static void pre_reset (ide_drive_t *drive)
if (!drive->keep_settings) {
drive->unmask = 0;
drive->io_32bit = 0;
- if (drive->using_dma) {
- drive->using_dma = 0;
- printk("%s: disabled DMA\n", drive->name);
- }
+ if (drive->using_dma)
+ HWIF(drive)->dmaproc(ide_dma_off, drive);
}
if (drive->driver != NULL)
DRIVER(drive)->pre_reset(drive);
@@ -820,7 +823,8 @@ void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err)
}
save_flags(flags);
cli();
- blk_dev[MAJOR(rq->rq_dev)].current_request = rq->next;
+ drive->queue = rq->next;
+ blk_dev[MAJOR(rq->rq_dev)].current_request = NULL;
HWGROUP(drive)->rq = NULL;
rq->rq_status = RQ_INACTIVE;
if (rq->sem != NULL)
@@ -840,21 +844,19 @@ byte ide_dump_status (ide_drive_t *drive, const char *msg, byte stat)
ide_sti();
printk("%s: %s: status=0x%02x", drive->name, msg, stat);
#if FANCY_STATUS_DUMPS
- if (drive->media == ide_disk) {
- printk(" { ");
- if (stat & BUSY_STAT)
- printk("Busy ");
- else {
- if (stat & READY_STAT) printk("DriveReady ");
- if (stat & WRERR_STAT) printk("DeviceFault ");
- if (stat & SEEK_STAT) printk("SeekComplete ");
- if (stat & DRQ_STAT) printk("DataRequest ");
- if (stat & ECC_STAT) printk("CorrectedError ");
- if (stat & INDEX_STAT) printk("Index ");
- if (stat & ERR_STAT) printk("Error ");
- }
- printk("}");
+ printk(" { ");
+ if (stat & BUSY_STAT)
+ printk("Busy ");
+ else {
+ if (stat & READY_STAT) printk("DriveReady ");
+ if (stat & WRERR_STAT) printk("DeviceFault ");
+ if (stat & SEEK_STAT) printk("SeekComplete ");
+ if (stat & DRQ_STAT) printk("DataRequest ");
+ if (stat & ECC_STAT) printk("CorrectedError ");
+ if (stat & INDEX_STAT) printk("Index ");
+ if (stat & ERR_STAT) printk("Error ");
}
+ printk("}");
#endif /* FANCY_STATUS_DUMPS */
printk("\n");
if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
@@ -907,6 +909,8 @@ static void try_to_flush_leftover_data (ide_drive_t *drive)
{
int i = (drive->mult_count ? drive->mult_count : 1) * SECTOR_WORDS;
+ if (drive->media != ide_disk)
+ return;
while (i > 0) {
unsigned long buffer[16];
unsigned int wcount = (i > 16) ? 16 : i;
@@ -951,7 +955,8 @@ void ide_error (ide_drive_t *drive, const char *msg, byte stat)
if (rq->errors >= ERROR_MAX) {
if (drive->driver != NULL)
DRIVER(drive)->end_request(0, HWGROUP(drive));
- ide_end_request(0, HWGROUP(drive));
+ else
+ ide_end_request(0, HWGROUP(drive));
} else {
if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
++rq->errors;
@@ -1093,24 +1098,20 @@ static void execute_drive_cmd (ide_drive_t *drive, struct request *rq)
/*
* do_request() initiates handling of a new I/O request
*/
-static inline void do_request (ide_hwif_t *hwif, struct request *rq)
+static inline void do_request (ide_hwgroup_t *hwgroup, ide_hwif_t *hwif, ide_drive_t *drive)
{
- unsigned int minor, unit;
unsigned long block, blockend;
- ide_drive_t *drive = NULL;
+ struct request *rq = drive->queue;
+ unsigned int minor = MINOR(rq->rq_dev), unit = minor >> PARTN_BITS;
ide_sti();
#ifdef DEBUG
printk("%s: do_request: current=0x%08lx\n", hwif->name, (unsigned long) rq);
#endif
- minor = MINOR(rq->rq_dev);
- unit = minor >> PARTN_BITS;
- if (MAJOR(rq->rq_dev) != hwif->major || unit >= MAX_DRIVES) {
- printk("%s: bad device number: %s\n",
- hwif->name, kdevname(rq->rq_dev));
+ if (unit >= MAX_DRIVES) {
+ printk("%s: bad device number: %s\n", hwif->name, kdevname(rq->rq_dev));
goto kill_rq;
}
- drive = &hwif->drives[unit];
#ifdef DEBUG
if (rq->bh && !buffer_locked(rq->bh)) {
printk("%s: block not locked\n", drive->name);
@@ -1129,17 +1130,18 @@ static inline void do_request (ide_hwif_t *hwif, struct request *rq)
if (block == 0 && drive->remap_0_to_1)
block = 1; /* redirect MBR access to EZ-Drive partn table */
#endif /* FAKE_FDISK_FOR_EZDRIVE */
- ((ide_hwgroup_t *)hwif->hwgroup)->drive = drive;
#if (DISK_RECOVERY_TIME > 0)
while ((read_timer() - hwif->last_time) < DISK_RECOVERY_TIME);
#endif
- SELECT_DRIVE(hwif,drive);
+ hwgroup->hwif = hwif;
+ hwgroup->drive = drive;
+ SELECT_DRIVE(hwif, drive);
if (ide_wait_stat(drive, drive->ready_stat, BUSY_STAT|DRQ_STAT, WAIT_READY)) {
printk("%s: drive not ready for command\n", drive->name);
return;
}
-
+
if (!drive->special.all) {
if (rq->cmd == IDE_DRIVE_CMD) {
execute_drive_cmd(drive, rq);
@@ -1155,10 +1157,95 @@ static inline void do_request (ide_hwif_t *hwif, struct request *rq)
do_special(drive);
return;
kill_rq:
- if (drive != NULL && drive->driver != NULL)
+ if (drive->driver != NULL)
DRIVER(drive)->end_request(0, HWGROUP(drive));
else
- ide_end_request(0, hwif->hwgroup);
+ ide_end_request(0, hwgroup);
+}
+
+/*
+ * ide_stall_queue() can be used by a drive to give excess bandwidth back
+ * to the hwgroup by sleeping for timeout jiffies.
+ */
+void ide_stall_queue (ide_drive_t *drive, unsigned long timeout)
+{
+ if (timeout > WAIT_WORSTCASE)
+ timeout = WAIT_WORSTCASE;
+ drive->sleep = timeout + jiffies;
+}
+
+#define WAKEUP(drive) ((drive)->service_start + 2 * (drive)->service_time)
+
+/*
+ * choose_drive() selects the next drive which will be serviced.
+ */
+static inline ide_drive_t *choose_drive (ide_hwgroup_t *hwgroup)
+{
+ ide_drive_t *drive, *best;
+
+repeat:
+ best = NULL;
+ drive = hwgroup->drive;
+ do {
+ if (!drive->queue)
+ continue;
+ if (drive->sleep && drive->sleep > jiffies)
+ continue;
+ if (!best) {
+ best = drive;
+ continue;
+ }
+ if (drive->sleep && (!best->sleep || drive->sleep < best->sleep))
+ best = drive;
+ if (!best->sleep && WAKEUP(drive) < WAKEUP(best))
+ best = drive;
+ } while ((drive = drive->next) != hwgroup->drive);
+ if (best != hwgroup->drive && best && best->service_time > WAIT_MIN_SLEEP && !best->sleep && best->nice1) {
+ long t = (signed) (WAKEUP(best) - jiffies);
+ if (t >= WAIT_MIN_SLEEP) {
+ /*
+ * We *may* have some time to spare, but first let's see if
+ * someone can potentially benefit from our nice mood today..
+ */
+ drive = best->next;
+ do {
+ if (drive->sleep) /* this drive tried to be nice to us */
+ continue;
+ if (WAKEUP(drive) > jiffies - best->service_time && WAKEUP(drive) < jiffies + t) {
+ ide_stall_queue(best, IDE_MIN(t, 10 * WAIT_MIN_SLEEP));
+ goto repeat;
+ }
+ } while ((drive = drive->next) != best);
+ }
+ }
+ return best;
+}
+
+static inline void ide_leave_hwgroup (ide_hwgroup_t *hwgroup)
+{
+ ide_drive_t *drive = hwgroup->drive;
+ unsigned long sleep = 0;
+
+ hwgroup->rq = NULL;
+ do {
+ blk_dev[HWIF(drive)->major].current_request = NULL;
+ if (!drive->sleep)
+ continue;
+ if (!sleep) {
+ sleep = drive->sleep;
+ continue;
+ }
+ if (drive->sleep < sleep)
+ sleep = drive->sleep;
+ } while ((drive = drive->next) != hwgroup->drive);
+ if (sleep) {
+ if (sleep < jiffies + WAIT_MIN_SLEEP)
+ sleep = jiffies + WAIT_MIN_SLEEP;
+ hwgroup->timer.expires = sleep;
+ add_timer(&hwgroup->timer);
+ } else /* Ugly, but how can we sleep for the lock otherwise? perhaps from tq_scheduler? */
+ ide_release_lock(&ide_lock);
+ hwgroup->active = 0;
}
/*
@@ -1184,32 +1271,35 @@ void ide_do_request (ide_hwgroup_t *hwgroup)
return;
}
do {
- ide_hwif_t *hwif = hwgroup->hwif;
- struct request *rq;
- if ((rq = hwgroup->rq) == NULL) {
- if (hwif->sharing_irq && hwgroup->drive) /* set nIEN */
- OUT_BYTE(hwgroup->drive->ctl|2,hwif->io_ports[IDE_CONTROL_OFFSET]);
- /*
- * hwgroup->next_hwif is different from hwgroup->hwif
- * only when a request is inserted using "ide_next".
- * This saves wear and tear on IDE tapes.
- */
- hwif = hwgroup->next_hwif;
- do {
- rq = blk_dev[hwif->major].current_request;
- if (rq != NULL && rq->rq_status != RQ_INACTIVE)
- goto got_rq;
- } while ((hwif = hwif->next) != hwgroup->next_hwif);
- ide_release_lock(&ide_lock);
- return; /* no work left for this hwgroup */
+ ide_drive_t *drive = choose_drive(hwgroup);
+ if (drive != NULL) {
+ ide_hwif_t *hwif = HWIF(drive);
+ if (hwgroup->hwif->sharing_irq && hwif != hwgroup->hwif)
+ OUT_BYTE(hwgroup->drive->ctl|2, hwgroup->hwif->io_ports[IDE_CONTROL_OFFSET]);
+ drive->sleep = 0;
+ blk_dev[hwif->major].current_request = hwgroup->rq = drive->queue;
+ drive->service_start = jiffies;
+ do_request(hwgroup, hwif, drive);
+ cli();
+ } else {
+ ide_leave_hwgroup(hwgroup); /* no work left for this hwgroup */
+ return;
}
- got_rq:
- do_request(hwgroup->hwif = hwgroup->next_hwif = hwif, hwgroup->rq = rq);
- cli();
} while (hwgroup->handler == NULL);
}
/*
+ * ide_get_queue() returns the queue which corresponds to a given device.
+ */
+struct request **ide_get_queue (kdev_t dev)
+{
+ struct blk_dev_struct *bdev = blk_dev + MAJOR(dev);
+ ide_hwif_t *hwif = bdev->data;
+
+ return &hwif->drives[DEVICE_NR(dev) & 1].queue;
+}
+
+/*
* do_hwgroup_request() invokes ide_do_request() after first masking
* all possible interrupts for the current hwgroup. This prevents race
* conditions in the event that an unexpected interrupt occurs while
@@ -1226,7 +1316,9 @@ static void do_hwgroup_request (ide_hwgroup_t *hwgroup)
ide_hwif_t *hgif = hwgroup->hwif;
ide_hwif_t *hwif = hgif;
+ del_timer(&hwgroup->timer);
ide_get_lock(&ide_lock, ide_intr, hwgroup);
+ hwgroup->active = 1;
do {
disable_irq(hwif->irq);
} while ((hwif = hwif->next) != hgif);
@@ -1267,25 +1359,28 @@ void ide_timer_expiry (unsigned long data)
{
ide_hwgroup_t *hwgroup = (ide_hwgroup_t *) data;
ide_drive_t *drive = hwgroup->drive;
+ ide_handler_t *handler;
unsigned long flags;
save_flags(flags);
cli();
- if (hwgroup->poll_timeout != 0) { /* polling in progress? */
- ide_handler_t *handler = hwgroup->handler;
+ if ((handler = hwgroup->handler) != NULL) {
hwgroup->handler = NULL;
- handler(drive);
- } else if (hwgroup->handler == NULL) { /* not waiting for anything? */
- ide_sti(); /* drive must have responded just as the timer expired */
- printk("%s: marginal timeout\n", drive->name);
- } else {
- hwgroup->handler = NULL; /* abort the operation */
- if (hwgroup->hwif->dmaproc)
- (void) hwgroup->hwif->dmaproc (ide_dma_abort, drive);
- ide_error(drive, "irq timeout", GET_STAT());
- }
- if (hwgroup->handler == NULL)
+ if (hwgroup->poll_timeout != 0) /* polling in progress? */
+ handler(drive);
+ else { /* abort the operation */
+ if (hwgroup->hwif->dmaproc)
+ (void) hwgroup->hwif->dmaproc (ide_dma_abort, drive);
+ ide_error(drive, "irq timeout", GET_STAT());
+ }
+ cli();
+ if (hwgroup->handler == NULL) {
+ set_recovery_timer(HWIF(drive));
+ drive->service_time = jiffies - drive->service_start;
+ do_hwgroup_request (hwgroup);
+ }
+ } else
do_hwgroup_request (hwgroup);
restore_flags(flags);
}
@@ -1355,7 +1450,7 @@ void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
ide_hwgroup_t *hwgroup = dev_id;
ide_handler_t *handler;
- if (!ide_ack_intr (hwgroup->hwif->io_ports[IDE_DATA_OFFSET],
+ if (!ide_ack_intr (hwgroup->hwif->io_ports[IDE_STATUS_OFFSET],
hwgroup->hwif->io_ports[IDE_IRQ_OFFSET]))
return;
@@ -1368,7 +1463,8 @@ void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
handler(drive);
cli(); /* this is necessary, as next rq may be different irq */
if (hwgroup->handler == NULL) {
- SET_RECOVERY_TIMER(HWIF(drive));
+ set_recovery_timer(HWIF(drive));
+ drive->service_time = jiffies - drive->service_start;
ide_do_request(hwgroup);
}
} else {
@@ -1394,9 +1490,6 @@ static ide_drive_t *get_info_ptr (kdev_t i_rdev)
ide_drive_t *drive = &hwif->drives[unit];
if (drive->present)
return drive;
- } else if (major == IDE0_MAJOR && unit < 4) {
- printk("ide: probable bad entry for /dev/hd%c\n", 'a'+unit);
- printk("ide: to fix it, run: /usr/src/linux/scripts/MAKEDEV.ide\n");
}
break;
}
@@ -1443,15 +1536,14 @@ void ide_init_drive_cmd (struct request *rq)
* If action is ide_end, then the rq is queued at the end of the
* request queue, and the function returns immediately without waiting
* for the new rq to be completed. This is again intended for careful
- * use by the ATAPI tape/cdrom driver code. (Currently used by ide-tape.c,
- * when operating in the pipelined operation mode).
+ * use by the ATAPI tape/cdrom driver code.
*/
int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t action)
{
unsigned long flags;
+ ide_hwgroup_t *hwgroup = HWGROUP(drive);
unsigned int major = HWIF(drive)->major;
struct request *cur_rq;
- struct blk_dev_struct *bdev = &blk_dev[major];
struct semaphore sem = MUTEX_LOCKED;
if (IS_PROMISE_DRIVE && rq->buffer != NULL)
@@ -1461,24 +1553,16 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio
rq->rq_dev = MKDEV(major,(drive->select.b.unit)<<PARTN_BITS);
if (action == ide_wait)
rq->sem = &sem;
- unplug_device(bdev);
save_flags(flags);
cli();
- if (action == ide_next)
- HWGROUP(drive)->next_hwif = HWIF(drive);
- cur_rq = bdev->current_request;
+ cur_rq = drive->queue;
if (cur_rq == NULL || action == ide_preempt) {
rq->next = cur_rq;
- bdev->current_request = rq;
- if (action == ide_preempt) {
- HWGROUP(drive)->rq = NULL;
- } else
- if (HWGROUP(drive)->rq == NULL) { /* is this necessary (?) */
- bdev->request_fn();
- cli();
- }
+ drive->queue = rq;
+ if (action == ide_preempt)
+ hwgroup->rq = NULL;
} else {
if (action == ide_wait || action == ide_end) {
while (cur_rq->next != NULL) /* find end of list */
@@ -1487,6 +1571,10 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio
rq->next = cur_rq->next;
cur_rq->next = rq;
}
+ if (!hwgroup->active) {
+ do_hwgroup_request(hwgroup);
+ cli();
+ }
if (action == ide_wait && rq->rq_status != RQ_INACTIVE)
down(&sem); /* wait for it to be serviced */
restore_flags(flags);
@@ -1533,7 +1621,8 @@ int ide_revalidate_disk(kdev_t i_rdev)
};
drive->part[0].nr_sects = current_capacity(drive);
- if (drive->media != ide_disk || drive->driver == NULL)
+ if ((drive->media != ide_disk && drive->media != ide_floppy) ||
+ drive->driver == NULL || !drive->part[0].nr_sects)
drive->part[0].start_sect = -1;
resetup_one_dev(HWIF(drive)->gd, drive->select.b.unit);
@@ -1564,14 +1653,21 @@ static void revalidate_drives (void)
static void ide_init_module (int type)
{
+ int found = 0;
ide_module_t *module = ide_modules;
while (module) {
- if (module->type == type)
+ if (module->type == type) {
+ found = 1;
(void) module->init();
+ }
module = module->next;
}
revalidate_drives();
+#ifdef CONFIG_KERNELD
+ if (!found && type == IDE_PROBE_MODULE)
+ (void) request_module("ide-probe");
+#endif /* CONFIG_KERNELD */
}
static int ide_open(struct inode * inode, struct file * filp)
@@ -1614,7 +1710,7 @@ static int ide_open(struct inode * inode, struct file * filp)
* Releasing a block device means we sync() it, so that it can safely
* be forgotten about...
*/
-static void ide_release(struct inode * inode, struct file * file)
+static int ide_release(struct inode * inode, struct file * file)
{
ide_drive_t *drive;
@@ -1625,12 +1721,13 @@ static void ide_release(struct inode * inode, struct file * file)
DRIVER(drive)->release(inode, file, drive);
MOD_DEC_USE_COUNT;
}
+ return 0;
}
void ide_unregister (unsigned int index)
{
struct gendisk *gd, **gdp;
- ide_drive_t *drive;
+ ide_drive_t *drive, *d;
ide_hwif_t *hwif, *g;
ide_hwgroup_t *hwgroup;
int irq_count = 0, unit;
@@ -1651,11 +1748,6 @@ void ide_unregister (unsigned int index)
goto abort;
if (drive->driver != NULL && DRIVER(drive)->cleanup(drive))
goto abort;
- if (drive->id != NULL) {
- kfree(drive->id);
- drive->id = NULL;
- }
- drive->present = 0;
}
hwif->present = 0;
hwgroup = hwif->hwgroup;
@@ -1684,15 +1776,31 @@ void ide_unregister (unsigned int index)
* Remove us from the hwgroup, and free
* the hwgroup if we were the only member
*/
+ d = hwgroup->drive;
+ for (index = 0; index < MAX_DRIVES; ++index) {
+ drive = &hwif->drives[index];
+ if (!drive->present)
+ continue;
+ while (hwgroup->drive->next != drive)
+ hwgroup->drive = hwgroup->drive->next;
+ hwgroup->drive->next = drive->next;
+ if (hwgroup->drive == drive)
+ hwgroup->drive = NULL;
+ if (drive->id != NULL) {
+ kfree(drive->id);
+ drive->id = NULL;
+ }
+ drive->present = 0;
+ }
+ if (d->present)
+ hwgroup->drive = d;
while (hwgroup->hwif->next != hwif)
hwgroup->hwif = hwgroup->hwif->next;
hwgroup->hwif->next = hwif->next;
if (hwgroup->hwif == hwif)
- hwgroup->hwif = hwif->next;
- if (hwgroup->next_hwif == hwif)
- hwgroup->next_hwif = hwif->next;
- if (hwgroup->hwif == hwif)
kfree(hwgroup);
+ else
+ hwgroup->hwif = HWIF(hwgroup->drive);
/*
* Remove us from the kernel's knowledge
@@ -1700,6 +1808,8 @@ void ide_unregister (unsigned int index)
unregister_blkdev(hwif->major, hwif->name);
kfree(blksize_size[hwif->major]);
blk_dev[hwif->major].request_fn = NULL;
+ blk_dev[hwif->major].data = NULL;
+ blk_dev[hwif->major].queue = NULL;
blksize_size[hwif->major] = NULL;
for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next))
if (*gdp == hwif->gd)
@@ -1731,13 +1841,8 @@ int ide_register (int arg1, int arg2, int irq)
}
for (index = 0; index < MAX_HWIFS; ++index) {
hwif = &ide_hwifs[index];
- if (!hwif->present) {
- ide_init_hwif_ports(hwif->io_ports, data_port, &hwif->irq);
- if (ctl_port)
- hwif->io_ports[IDE_CONTROL_OFFSET] = ctl_port;
- hwif->irq = irq;
+ if (!hwif->present)
goto found;
- }
}
for (index = 0; index < MAX_HWIFS; index++)
ide_unregister(index);
@@ -1748,6 +1853,10 @@ found:
ide_unregister(index);
if (hwif->present)
return -1;
+ ide_init_hwif_ports(hwif->io_ports, data_port, &hwif->irq);
+ if (ctl_port)
+ hwif->io_ports[IDE_CONTROL_OFFSET] = ctl_port;
+ hwif->irq = irq;
hwif->noprobe = 0;
ide_init_module(IDE_PROBE_MODULE);
ide_init_module(IDE_DRIVER_MODULE);
@@ -1771,7 +1880,7 @@ static int ide_ioctl (struct inode *inode, struct file *file,
case HDIO_GETGEO:
{
struct hd_geometry *loc = (struct hd_geometry *) arg;
- if (!loc || drive->media != ide_disk) return -EINVAL;
+ if (!loc || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL;
if (put_user(drive->bios_head, (byte *) &loc->heads)) return -EFAULT;
if (put_user(drive->bios_sect, (byte *) &loc->sectors)) return -EFAULT;
if (put_user(drive->bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT;
@@ -1828,6 +1937,18 @@ static int ide_ioctl (struct inode *inode, struct file *file,
case HDIO_GET_NOWERR:
return put_user(drive->bad_wstat == BAD_R_STAT, (long *) arg);
+ case HDIO_GET_NICE:
+ {
+ long nice = 0;
+
+ nice |= drive->dsc_overlap << IDE_NICE_DSC_OVERLAP;
+ nice |= drive->atapi_overlap << IDE_NICE_ATAPI_OVERLAP;
+ nice |= drive->nice0 << IDE_NICE_0;
+ nice |= drive->nice1 << IDE_NICE_1;
+ nice |= drive->nice2 << IDE_NICE_2;
+ return put_user(nice, (long *) arg);
+ }
+
case HDIO_SET_DMA:
if (!suser()) return -EACCES;
if (drive->driver != NULL && !DRIVER(drive)->supports_dma)
@@ -1851,7 +1972,10 @@ static int ide_ioctl (struct inode *inode, struct file *file,
restore_flags(flags);
return -EPERM;
}
- drive->using_dma = arg;
+ if (HWIF(drive)->dmaproc(arg ? ide_dma_on : ide_dma_off, drive)) {
+ restore_flags(flags);
+ return -EIO;
+ }
break;
case HDIO_SET_KEEPSETTINGS:
drive->keep_settings = arg;
@@ -1955,6 +2079,19 @@ static int ide_ioctl (struct inode *inode, struct file *file,
return -EIO;
return 0;
}
+ case HDIO_SET_NICE:
+ if (!suser()) return -EACCES;
+ if (drive->driver == NULL)
+ return -EPERM;
+ if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP) | (1 << IDE_NICE_1))))
+ return -EPERM;
+ drive->dsc_overlap = (arg >> IDE_NICE_DSC_OVERLAP) & 1;
+ if (drive->dsc_overlap && !DRIVER(drive)->supports_dsc_overlap) {
+ drive->dsc_overlap = 0;
+ return -EPERM;
+ }
+ drive->nice1 = (arg >> IDE_NICE_1) & 1;
+ return 0;
RO_IOCTLS(inode->i_rdev, arg);
@@ -2058,7 +2195,7 @@ static int match_parm (char *s, const char *keywords[], int vals[], int max_vals
}
if (++n == max_vals)
break;
- if (*s == ',')
+ if (*s == ',' || *s == ';')
++s;
}
if (!*s)
@@ -2439,10 +2576,10 @@ static void ide_probe_pci (unsigned short vendor, unsigned short device, ide_pci
#endif /* CONFIG_PCI */
/*
- * ide_init_pci() finds/initializes "known" PCI IDE interfaces
+ * probe_for_hwifs() finds/initializes "known" IDE interfaces
*
- * This routine should ideally be using pcibios_find_class() to find
- * all IDE interfaces, but that function causes some systems to "go weird".
+ * This routine should ideally be using pcibios_find_class() to find all
+ * PCI IDE interfaces, but that function causes some systems to "go weird".
*/
static void probe_for_hwifs (void)
{
@@ -2465,6 +2602,7 @@ static void probe_for_hwifs (void)
*/
ide_probe_pci (PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371_0, &ide_init_triton, 1);
ide_probe_pci (PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_1, &ide_init_triton, 0);
+ ide_probe_pci (PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB, &ide_init_triton, 0);
#endif /* CONFIG_BLK_DEV_TRITON */
#ifdef CONFIG_BLK_DEV_OPTI621
ide_probe_pci (PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C621, &ide_init_opti621, 0);
@@ -2489,10 +2627,13 @@ void ide_init_builtin_drivers (void)
*/
probe_for_hwifs ();
+ /*
+ * Probe for devices
+ */
#ifdef CONFIG_BLK_DEV_IDE
#ifdef __mc68000__
if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET]) {
- ide_get_lock(&ide_lock, ide_intr, NULL);
+ ide_get_lock(&ide_lock, NULL, NULL);
disable_irq(ide_hwifs[0].irq);
}
#endif /* __mc68000__ */
@@ -2507,6 +2648,9 @@ void ide_init_builtin_drivers (void)
#endif /* __mc68000__ */
#endif /* CONFIG_BLK_DEV_IDE */
+ /*
+ * Attempt to match drivers for the available drives
+ */
#ifdef CONFIG_BLK_DEV_IDEDISK
(void) idedisk_init();
#endif /* CONFIG_BLK_DEV_IDEDISK */
@@ -2519,6 +2663,9 @@ void ide_init_builtin_drivers (void)
#ifdef CONFIG_BLK_DEV_IDEFLOPPY
(void) idefloppy_init();
#endif /* CONFIG_BLK_DEV_IDEFLOPPY */
+#ifdef CONFIG_BLK_DEV_IDESCSI
+ (void) idescsi_init();
+#endif /* CONFIG_BLK_DEV_IDESCSI */
}
static int default_cleanup (ide_drive_t *drive)
@@ -2595,6 +2742,10 @@ ide_drive_t *ide_scan_devices (byte media, ide_driver_t *driver, int n)
unsigned int unit, index, i;
ide_drive_t *drive;
+ for (index = 0; index < MAX_HWIFS; ++index)
+ if (ide_hwifs[index].present) goto search;
+ ide_init_module(IDE_PROBE_MODULE);
+search:
for (index = 0, i = 0; index < MAX_HWIFS; ++index) {
for (unit = 0; unit < MAX_DRIVES; ++unit) {
drive = &ide_hwifs[index].drives[unit];
@@ -2613,15 +2764,19 @@ int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int versio
save_flags(flags);
cli();
if (version != IDE_SUBDRIVER_VERSION || !drive->present || drive->driver != NULL ||
- drive->busy || drive->usage || drive->media != driver->media) {
+ drive->busy || drive->usage) {
restore_flags(flags);
return 1;
}
drive->driver = driver;
setup_driver_defaults(drive);
restore_flags(flags);
- if (driver->supports_dma && !drive->using_dma && drive->autotune != 2 && HWIF(drive)->dmaproc != NULL)
- (void) (HWIF(drive)->dmaproc(ide_dma_check, drive));
+ if (drive->autotune != 2) {
+ if (driver->supports_dma && HWIF(drive)->dmaproc != NULL)
+ (void) (HWIF(drive)->dmaproc(ide_dma_check, drive));
+ drive->dsc_overlap = (drive->next != drive && driver->supports_dsc_overlap);
+ drive->nice1 = 1;
+ }
drive->revalidate = 1;
return 0;
}
@@ -2670,7 +2825,7 @@ struct file_operations ide_fops[] = {{
block_read, /* read - general block-dev read */
block_write, /* write - general block-dev write */
NULL, /* readdir - bad */
- NULL, /* select */
+ NULL, /* poll */
ide_ioctl, /* ioctl */
NULL, /* mmap */
ide_open, /* open */
@@ -2681,44 +2836,55 @@ struct file_operations ide_fops[] = {{
ide_revalidate_disk /* revalidate */
}};
-static struct symbol_table ide_syms = {
-#include <linux/symtab_begin.h>
- X(ide_hwifs),
- X(ide_register_module), X(ide_unregister_module),
+EXPORT_SYMBOL(ide_hwifs);
+EXPORT_SYMBOL(ide_register_module);
+EXPORT_SYMBOL(ide_unregister_module);
- /*
- * Probe module
- */
- X(ide_timer_expiry), X(ide_intr),
- X(ide_geninit), X(ide_fops),
- X(do_ide0_request),
+/*
+ * Probe module
+ */
+EXPORT_SYMBOL(ide_timer_expiry);
+EXPORT_SYMBOL(ide_intr);
+EXPORT_SYMBOL(ide_geninit);
+EXPORT_SYMBOL(ide_fops);
+EXPORT_SYMBOL(ide_get_queue);
+EXPORT_SYMBOL(do_ide0_request);
#if MAX_HWIFS > 1
- X(do_ide1_request),
+EXPORT_SYMBOL(do_ide1_request);
#endif /* MAX_HWIFS > 1 */
#if MAX_HWIFS > 2
- X(do_ide2_request),
+EXPORT_SYMBOL(do_ide2_request);
#endif /* MAX_HWIFS > 2 */
#if MAX_HWIFS > 3
- X(do_ide3_request),
+EXPORT_SYMBOL(do_ide3_request);
#endif /* MAX_HWIFS > 3 */
- /*
- * Driver module
- */
- X(ide_scan_devices), X(ide_register_subdriver),
- X(ide_unregister_subdriver), X(ide_input_data),
- X(ide_output_data), X(atapi_input_bytes),
- X(atapi_output_bytes), X(ide_set_handler),
- X(ide_dump_status), X(ide_error),
- X(ide_fixstring), X(ide_wait_stat),
- X(ide_do_reset), X(ide_init_drive_cmd),
- X(ide_do_drive_cmd), X(ide_end_drive_cmd),
- X(ide_end_request), X(ide_revalidate_disk),
- X(ide_cmd),
-
- X(ide_register), X(ide_unregister),
-#include <linux/symtab_end.h>
-};
+/*
+ * Driver module
+ */
+EXPORT_SYMBOL(ide_scan_devices);
+EXPORT_SYMBOL(ide_register_subdriver);
+EXPORT_SYMBOL(ide_unregister_subdriver);
+EXPORT_SYMBOL(ide_input_data);
+EXPORT_SYMBOL(ide_output_data);
+EXPORT_SYMBOL(atapi_input_bytes);
+EXPORT_SYMBOL(atapi_output_bytes);
+EXPORT_SYMBOL(ide_set_handler);
+EXPORT_SYMBOL(ide_dump_status);
+EXPORT_SYMBOL(ide_error);
+EXPORT_SYMBOL(ide_fixstring);
+EXPORT_SYMBOL(ide_wait_stat);
+EXPORT_SYMBOL(ide_do_reset);
+EXPORT_SYMBOL(ide_init_drive_cmd);
+EXPORT_SYMBOL(ide_do_drive_cmd);
+EXPORT_SYMBOL(ide_end_drive_cmd);
+EXPORT_SYMBOL(ide_end_request);
+EXPORT_SYMBOL(ide_revalidate_disk);
+EXPORT_SYMBOL(ide_cmd);
+EXPORT_SYMBOL(ide_stall_queue);
+
+EXPORT_SYMBOL(ide_register);
+EXPORT_SYMBOL(ide_unregister);
/*
* This is gets invoked once during initialization, to set *everything* up
@@ -2731,12 +2897,12 @@ int ide_init (void)
ide_init_builtin_drivers();
initializing = 0;
- (void) register_symtab(&ide_syms);
return 0;
}
#ifdef MODULE
char *options = NULL;
+MODULE_PARM(options,"s");
static void parse_options (char *line)
{