From 19c9bba94152148523ba0f7ef7cffe3d45656b11 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 29 Apr 1997 21:13:14 +0000 Subject: Import of Linux/MIPS 2.1.36 --- drivers/block/ide.c | 496 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 331 insertions(+), 165 deletions(-) (limited to 'drivers/block/ide.c') 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 */ @@ -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 #include #include +#include +#include #include #include @@ -301,11 +314,6 @@ #include #include -#ifdef CONFIG_PCI -#include -#include -#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,31 +1271,34 @@ 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 @@ -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)<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 - 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 -}; +/* + * 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) { -- cgit v1.2.3