summaryrefslogtreecommitdiffstats
path: root/drivers/block/ide.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1998-03-17 22:05:47 +0000
committerRalf Baechle <ralf@linux-mips.org>1998-03-17 22:05:47 +0000
commit27cfca1ec98e91261b1a5355d10a8996464b63af (patch)
tree8e895a53e372fa682b4c0a585b9377d67ed70d0e /drivers/block/ide.c
parent6a76fb7214c477ccf6582bd79c5b4ccc4f9c41b1 (diff)
Look Ma' what I found on my harddisk ...
o New faster syscalls for 2.1.x, too o Upgrade to 2.1.89. Don't try to run this. It's flaky as hell. But feel free to debug ...
Diffstat (limited to 'drivers/block/ide.c')
-rw-r--r--drivers/block/ide.c563
1 files changed, 334 insertions, 229 deletions
diff --git a/drivers/block/ide.c b/drivers/block/ide.c
index 3b9a17283..7ec27d45d 100644
--- a/drivers/block/ide.c
+++ b/drivers/block/ide.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide.c Version 6.11 December 5, 1997
+ * linux/drivers/block/ide.c Version 6.12 January 2, 1998
*
* Copyright (C) 1994-1998 Linus Torvalds & authors (see below)
*/
@@ -98,6 +98,8 @@
* Version 6.11 fix probe error in ide_scan_devices()
* fix ancient "jiffies" polling bugs
* mask all hwgroup interrupts on each irq entry
+ * Version 6.12 integrate ioctl and proc interfaces
+ * fix parsing of "idex=" command line parameter
*
* Some additional driver compile-time options are in ide.h
*
@@ -151,7 +153,7 @@ static int ide_lock = 0;
/*
* ide_modules keeps track of the available IDE chipset/probe/driver modules.
*/
-static ide_module_t *ide_modules = NULL;
+ide_module_t *ide_modules = NULL;
/*
* This is declared extern in ide.h, for access by other IDE modules:
@@ -168,13 +170,13 @@ static unsigned long read_timer(void)
unsigned long t, flags;
int i;
- save_flags(flags);
- cli();
+ __save_flags(flags);
+ __cli();
t = jiffies * 11932;
outb_p(0, 0x43);
i = inb_p(0x40);
i |= inb(0x40) << 8;
- restore_flags(flags);
+ __restore_flags(flags);
return (t - i);
}
#endif /* DISK_RECOVERY_TIME */
@@ -312,11 +314,11 @@ void ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
#if SUPPORT_VLB_SYNC
if (io_32bit & 2) {
unsigned long flags;
- save_flags(flags);
- cli();
+ __save_flags(flags);
+ __cli();
do_vlb_sync(IDE_NSECTOR_REG);
insl(IDE_DATA_REG, buffer, wcount);
- restore_flags(flags);
+ __restore_flags(flags);
} else
#endif /* SUPPORT_VLB_SYNC */
insl(IDE_DATA_REG, buffer, wcount);
@@ -345,11 +347,11 @@ void ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
#if SUPPORT_VLB_SYNC
if (io_32bit & 2) {
unsigned long flags;
- save_flags(flags);
- cli();
+ __save_flags(flags);
+ __cli();
do_vlb_sync(IDE_NSECTOR_REG);
outsl(IDE_DATA_REG, buffer, wcount);
- restore_flags(flags);
+ __restore_flags(flags);
} else
#endif /* SUPPORT_VLB_SYNC */
outsl(IDE_DATA_REG, buffer, wcount);
@@ -571,8 +573,8 @@ static void do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
ide_hwif_t *hwif = HWIF(drive);
ide_hwgroup_t *hwgroup = HWGROUP(drive);
- save_flags(flags);
- cli(); /* Why ? */
+ __save_flags(flags);
+ __cli(); /* Why ? */
/* For an ATAPI device, first try an ATAPI SRST. */
if (drive->media != ide_disk && !do_not_try_atapi) {
@@ -582,7 +584,7 @@ static void do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
OUT_BYTE (WIN_SRST, IDE_COMMAND_REG);
hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20);
- restore_flags (flags);
+ __restore_flags (flags);
return;
}
@@ -610,7 +612,7 @@ static void do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
ide_set_handler (drive, &reset_pollfunc, HZ/20);
#endif /* OK_TO_RESET_CONTROLLER */
- restore_flags (flags);
+ __restore_flags (flags);
}
/*
@@ -638,15 +640,15 @@ void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err)
args[2] = IN_BYTE(IDE_NSECTOR_REG);
}
}
- save_flags(flags);
- cli();
+ __save_flags(flags);
+ __cli();
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)
up(rq->sem);
- restore_flags(flags);
+ __restore_flags(flags);
}
/*
@@ -657,8 +659,8 @@ byte ide_dump_status (ide_drive_t *drive, const char *msg, byte stat)
unsigned long flags;
byte err = 0;
- save_flags (flags);
- ide_sti();
+ __save_flags (flags);
+ /* ide_sti(); HACK */
printk("%s: %s: status=0x%02x", drive->name, msg, stat);
#if FANCY_STATUS_DUMPS
printk(" { ");
@@ -711,7 +713,7 @@ byte ide_dump_status (ide_drive_t *drive, const char *msg, byte stat)
#endif /* FANCY_STATUS_DUMPS */
printk("\n");
}
- restore_flags (flags);
+ __restore_flags (flags);
return err;
}
@@ -809,20 +811,20 @@ static void drive_cmd_intr (ide_drive_t *drive)
{
struct request *rq = HWGROUP(drive)->rq;
byte *args = (byte *) rq->buffer;
- byte test, stat = GET_STAT();
+ byte stat = GET_STAT();
+ int retries = 10;
- ide_sti();
+ /* ide_sti(); HACK */
if ((stat & DRQ_STAT) && args && args[3]) {
byte io_32bit = drive->io_32bit;
drive->io_32bit = 0;
ide_input_data(drive, &args[4], args[3] * SECTOR_WORDS);
drive->io_32bit = io_32bit;
- stat = GET_STAT();
+ while (((stat = GET_STAT()) & BUSY_STAT) && retries--)
+ udelay(100);
}
- test = stat;
- if (drive->media == ide_cdrom)
- test = stat &~BUSY_STAT;
- if (OK_STAT(test,READY_STAT,BAD_STAT))
+
+ if (OK_STAT(stat, READY_STAT, BAD_STAT))
ide_end_drive_cmd (drive, stat, GET_ERR());
else
ide_error(drive, "drive_cmd", stat); /* calls ide_end_drive_cmd */
@@ -870,17 +872,17 @@ int ide_wait_stat (ide_drive_t *drive, byte good, byte bad, unsigned long timeou
udelay(1); /* spec allows drive 400ns to assert "BUSY" */
if ((stat = GET_STAT()) & BUSY_STAT) {
- save_flags(flags);
- ide_sti();
+ __save_flags(flags);
+ /* ide_sti(); HACK */
timeout += jiffies;
while ((stat = GET_STAT()) & BUSY_STAT) {
if (0 < (signed long)(jiffies - timeout)) {
- restore_flags(flags);
+ __restore_flags(flags);
ide_error(drive, "status timeout", stat);
return 1;
}
}
- restore_flags(flags);
+ __restore_flags(flags);
}
udelay(1); /* allow status to settle, then read it again */
if (OK_STAT((stat = GET_STAT()), good, bad))
@@ -901,6 +903,10 @@ static void execute_drive_cmd (ide_drive_t *drive, struct request *rq)
printk("%s: DRIVE_CMD cmd=0x%02x sc=0x%02x fr=0x%02x xx=0x%02x\n",
drive->name, args[0], args[1], args[2], args[3]);
#endif
+ if (args[0] == WIN_SMART) {
+ OUT_BYTE(0x4f, IDE_LCYL_REG);
+ OUT_BYTE(0xc2, IDE_HCYL_REG);
+ }
OUT_BYTE(args[2],IDE_FEATURE_REG);
ide_cmd(drive, args[0], args[1], &drive_cmd_intr);
return;
@@ -926,7 +932,7 @@ static inline void do_request (ide_hwgroup_t *hwgroup, ide_hwif_t *hwif, ide_dri
struct request *rq = drive->queue;
unsigned int minor = MINOR(rq->rq_dev), unit = minor >> PARTN_BITS;
- ide_sti();
+ /* ide_sti(); HACK */
#ifdef DEBUG
printk("%s: do_request: current=0x%08lx\n", hwif->name, (unsigned long) rq);
#endif
@@ -1087,7 +1093,7 @@ static inline void ide_leave_hwgroup (ide_hwgroup_t *hwgroup)
*/
void ide_do_request (ide_hwgroup_t *hwgroup)
{
- cli(); /* paranoia */
+ __cli(); /* paranoia */
if (hwgroup->handler != NULL) {
printk("%s: EEeekk!! handler not NULL in ide_do_request()\n", hwgroup->hwif->name);
return;
@@ -1102,7 +1108,7 @@ void ide_do_request (ide_hwgroup_t *hwgroup)
blk_dev[hwif->major].current_request = hwgroup->rq = drive->queue;
drive->service_start = jiffies;
do_request(hwgroup, hwif, drive);
- cli();
+ __cli();
} else {
ide_leave_hwgroup(hwgroup); /* no work left for this hwgroup */
return;
@@ -1151,27 +1157,27 @@ static void do_hwgroup_request (ide_hwgroup_t *hwgroup)
}
}
-void do_ide0_request (void) /* invoked with cli() */
+void do_ide0_request (void) /* invoked with __cli() */
{
do_hwgroup_request (ide_hwifs[0].hwgroup);
}
#if MAX_HWIFS > 1
-void do_ide1_request (void) /* invoked with cli() */
+void do_ide1_request (void) /* invoked with __cli() */
{
do_hwgroup_request (ide_hwifs[1].hwgroup);
}
#endif /* MAX_HWIFS > 1 */
#if MAX_HWIFS > 2
-void do_ide2_request (void) /* invoked with cli() */
+void do_ide2_request (void) /* invoked with __cli() */
{
do_hwgroup_request (ide_hwifs[2].hwgroup);
}
#endif /* MAX_HWIFS > 2 */
#if MAX_HWIFS > 3
-void do_ide3_request (void) /* invoked with cli() */
+void do_ide3_request (void) /* invoked with __cli() */
{
do_hwgroup_request (ide_hwifs[3].hwgroup);
}
@@ -1184,8 +1190,8 @@ void ide_timer_expiry (unsigned long data)
ide_handler_t *handler;
unsigned long flags;
- save_flags(flags);
- cli();
+ __save_flags(flags);
+ __cli();
if ((handler = hwgroup->handler) != NULL) {
hwgroup->handler = NULL;
@@ -1196,7 +1202,7 @@ void ide_timer_expiry (unsigned long data)
(void) hwgroup->hwif->dmaproc (ide_dma_end, drive);
ide_error(drive, "irq timeout", GET_STAT());
}
- cli();
+ __cli();
if (hwgroup->handler == NULL) {
set_recovery_timer(HWIF(drive));
drive->service_time = jiffies - drive->service_start;
@@ -1204,7 +1210,7 @@ void ide_timer_expiry (unsigned long data)
}
} else
do_hwgroup_request (hwgroup);
- restore_flags(flags);
+ __restore_flags(flags);
}
/*
@@ -1217,7 +1223,7 @@ void ide_timer_expiry (unsigned long data)
* drive enters "idle", "standby", or "sleep" mode, so if the status looks
* "good", we just ignore the interrupt completely.
*
- * This routine assumes cli() is in effect when called.
+ * This routine assumes __cli() is in effect when called.
*
* If an unexpected interrupt happens on irq15 while we are handling irq14
* and if the two interfaces are "serialized" (CMD640), then it looks like
@@ -1255,10 +1261,11 @@ static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup)
}
/*
- * entry point for all interrupts, caller does cli() for us
+ * entry point for all interrupts, caller does __cli() for us
*/
void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
{
+ unsigned long flags;
ide_hwgroup_t *hwgroup = dev_id;
ide_hwif_t *hwif = hwgroup->hwif;
ide_handler_t *handler;
@@ -1284,19 +1291,21 @@ void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
#endif /* temporary */
hwgroup->handler = NULL;
del_timer(&(hwgroup->timer));
- if (drive->unmask)
- ide_sti();
+ /* if (drive->unmask)
+ ide_sti(); HACK */
handler(drive);
- cli(); /* this is necessary, as next rq may be different irq */
+ /* this is necessary, as next rq may be different irq */
+ spin_lock_irqsave(&io_request_lock,flags);
if (hwgroup->handler == NULL) {
set_recovery_timer(HWIF(drive));
drive->service_time = jiffies - drive->service_start;
ide_do_request(hwgroup);
}
+ spin_unlock_irqrestore(&io_request_lock,flags);
} else {
unexpected_intr(irq, hwgroup);
}
- cli();
+ __cli();
hwif = hwgroup->hwif;
do {
if (hwif->irq != irq) enable_irq(hwif->irq);
@@ -1384,8 +1393,8 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio
if (action == ide_wait)
rq->sem = &sem;
- save_flags(flags);
- cli();
+ __save_flags(flags);
+ __cli();
cur_rq = drive->queue;
if (cur_rq == NULL || action == ide_preempt) {
@@ -1403,11 +1412,11 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio
}
if (!hwgroup->active) {
do_hwgroup_request(hwgroup);
- cli();
+ __cli();
}
if (action == ide_wait && rq->rq_status != RQ_INACTIVE)
down(&sem); /* wait for it to be serviced */
- restore_flags(flags);
+ __restore_flags(flags);
return rq->errors ? -EIO : 0; /* return -EIO if errors */
}
@@ -1429,15 +1438,15 @@ int ide_revalidate_disk(kdev_t i_rdev)
return -ENODEV;
major = MAJOR(i_rdev);
minor = drive->select.b.unit << PARTN_BITS;
- save_flags(flags);
- cli();
+ __save_flags(flags);
+ __cli();
if (drive->busy || (drive->usage > 1)) {
- restore_flags(flags);
+ __restore_flags(flags);
return -EBUSY;
};
drive->busy = 1;
MOD_INC_USE_COUNT;
- restore_flags(flags);
+ __restore_flags(flags);
for (p = 0; p < (1<<PARTN_BITS); ++p) {
if (drive->part[p].nr_sects > 0) {
@@ -1556,6 +1565,22 @@ static int ide_release(struct inode * inode, struct file * file)
return 0;
}
+int ide_replace_subdriver(ide_drive_t *drive, const char *driver)
+{
+ if (!drive->present || drive->busy || drive->usage)
+ goto abort;
+ if (drive->driver != NULL && DRIVER(drive)->cleanup(drive))
+ goto abort;
+ strncpy(drive->driver_req, driver, 9);
+ ide_init_module(IDE_DRIVER_MODULE);
+ drive->driver_req[0] = 0;
+ ide_init_module(IDE_DRIVER_MODULE);
+ if (DRIVER(drive) && !strcmp(DRIVER(drive)->name, driver))
+ return 0;
+abort:
+ return 1;
+}
+
void ide_unregister (unsigned int index)
{
struct gendisk *gd, **gdp;
@@ -1567,8 +1592,8 @@ void ide_unregister (unsigned int index)
if (index >= MAX_HWIFS)
return;
- save_flags(flags);
- cli();
+ __save_flags(flags);
+ __cli();
hwif = &ide_hwifs[index];
if (!hwif->present)
goto abort;
@@ -1640,6 +1665,7 @@ void ide_unregister (unsigned int index)
unregister_blkdev(hwif->major, hwif->name);
kfree(blksize_size[hwif->major]);
kfree(max_sectors[hwif->major]);
+ kfree(max_readahead[hwif->major]);
blk_dev[hwif->major].request_fn = NULL;
blk_dev[hwif->major].data = NULL;
blk_dev[hwif->major].queue = NULL;
@@ -1657,7 +1683,7 @@ void ide_unregister (unsigned int index)
}
init_hwif_data (index); /* restore hwif data to pristine status */
abort:
- restore_flags(flags);
+ __restore_flags(flags);
}
int ide_register (int arg1, int arg2, int irq)
@@ -1696,20 +1722,229 @@ found:
return hwif->present ? index : -1;
}
+void ide_add_setting(ide_drive_t *drive, char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set)
+{
+ ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting = NULL;
+
+ while ((*p) && strcmp((*p)->name, name) < 0)
+ p = &((*p)->next);
+ if ((setting = kmalloc(sizeof(*setting), GFP_KERNEL)) == NULL)
+ goto abort;
+ memset(setting, 0, sizeof(*setting));
+ if ((setting->name = kmalloc(strlen(name) + 1, GFP_KERNEL)) == NULL)
+ goto abort;
+ strcpy(setting->name, name); setting->rw = rw;
+ setting->read_ioctl = read_ioctl; setting->write_ioctl = write_ioctl;
+ setting->data_type = data_type; setting->min = min;
+ setting->max = max; setting->mul_factor = mul_factor;
+ setting->div_factor = div_factor; setting->data = data;
+ setting->set = set; setting->next = *p;
+ if (drive->driver)
+ setting->auto_remove = 1;
+ *p = setting;
+ return;
+abort:
+ if (setting)
+ kfree(setting);
+}
+
+void ide_remove_setting(ide_drive_t *drive, char *name)
+{
+ ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting;
+
+ while ((*p) && strcmp((*p)->name, name))
+ p = &((*p)->next);
+ if ((setting = (*p)) == NULL)
+ return;
+ (*p) = setting->next;
+ kfree(setting->name);
+ kfree(setting);
+}
+
+static ide_settings_t *ide_find_setting_by_ioctl(ide_drive_t *drive, int cmd)
+{
+ ide_settings_t *setting = drive->settings;
+
+ while (setting) {
+ if (setting->read_ioctl == cmd || setting->write_ioctl == cmd)
+ break;
+ setting = setting->next;
+ }
+ return setting;
+}
+
+ide_settings_t *ide_find_setting_by_name(ide_drive_t *drive, char *name)
+{
+ ide_settings_t *setting = drive->settings;
+
+ while (setting) {
+ if (strcmp(setting->name, name) == 0)
+ break;
+ setting = setting->next;
+ }
+ return setting;
+}
+
+static void auto_remove_settings(ide_drive_t *drive)
+{
+ ide_settings_t *setting;
+repeat:
+ setting = drive->settings;
+ while (setting) {
+ if (setting->auto_remove) {
+ ide_remove_setting(drive, setting->name);
+ goto repeat;
+ }
+ setting = setting->next;
+ }
+}
+
+int ide_read_setting(ide_drive_t *drive, ide_settings_t *setting)
+{
+ if (!(setting->rw & SETTING_READ))
+ return -EINVAL;
+ switch(setting->data_type) {
+ case TYPE_BYTE:
+ return *((u8 *) setting->data);
+ case TYPE_SHORT:
+ return *((u16 *) setting->data);
+ case TYPE_INT:
+ case TYPE_INTA:
+ return *((u32 *) setting->data);
+ default:
+ return -EINVAL;
+ }
+}
+
+int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int val)
+{
+ unsigned long flags;
+ int i, rc = 0;
+ u32 *p;
+
+ if (!suser())
+ return -EACCES;
+ if (!(setting->rw & SETTING_WRITE))
+ return -EPERM;
+ if (val < setting->min || val > setting->max)
+ return -EINVAL;
+ __save_flags(flags);
+ __cli();
+ if (setting->set)
+ rc = setting->set(drive, val);
+ else switch (setting->data_type) {
+ case TYPE_BYTE:
+ *((u8 *) setting->data) = val;
+ break;
+ case TYPE_SHORT:
+ *((u16 *) setting->data) = val;
+ break;
+ case TYPE_INT:
+ *((u32 *) setting->data) = val;
+ break;
+ case TYPE_INTA:
+ p = (u32 *) setting->data;
+ for (i = 0; i < 1 << PARTN_BITS; i++, p++)
+ *p = val;
+ break;
+ }
+ __restore_flags(flags);
+ return rc;
+}
+
+static int set_io_32bit(ide_drive_t *drive, int arg)
+{
+ drive->io_32bit = arg;
+#ifdef CONFIG_BLK_DEV_DTC2278
+ if (HWIF(drive)->chipset == ide_dtc2278)
+ HWIF(drive)->drives[!drive->select.b.unit].io_32bit = arg;
+#endif /* CONFIG_BLK_DEV_DTC2278 */
+ return 0;
+}
+
+static int set_using_dma(ide_drive_t *drive, int arg)
+{
+ if (!drive->driver || !DRIVER(drive)->supports_dma)
+ return -EPERM;
+ if (!drive->id || !(drive->id->capability & 1) || !HWIF(drive)->dmaproc)
+ return -EPERM;
+ if (HWIF(drive)->dmaproc(arg ? ide_dma_on : ide_dma_off, drive))
+ return -EIO;
+ return 0;
+}
+
+static int set_pio_mode(ide_drive_t *drive, int arg)
+{
+ struct request rq;
+
+ if (!HWIF(drive)->tuneproc)
+ return -ENOSYS;
+ if (drive->special.b.set_tune)
+ return -EBUSY;
+ ide_init_drive_cmd(&rq);
+ drive->tune_req = (byte) arg;
+ drive->special.b.set_tune = 1;
+ (void) ide_do_drive_cmd (drive, &rq, ide_wait);
+ return 0;
+}
+
+void ide_add_generic_settings(ide_drive_t *drive)
+{
+/*
+ * drive setting name read/write access read ioctl write ioctl data type min max mul_factor div_factor data pointer set function
+ */
+ ide_add_setting(drive, "io_32bit", drive->no_io_32bit ? SETTING_READ : SETTING_RW, HDIO_GET_32BIT, HDIO_SET_32BIT, TYPE_BYTE, 0, 1 + (SUPPORT_VLB_SYNC << 1), 1, 1, &drive->io_32bit, set_io_32bit);
+ ide_add_setting(drive, "keepsettings", SETTING_RW, HDIO_GET_KEEPSETTINGS, HDIO_SET_KEEPSETTINGS, TYPE_BYTE, 0, 1, 1, 1, &drive->keep_settings, NULL);
+ ide_add_setting(drive, "nice1", SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->nice1, NULL);
+ ide_add_setting(drive, "pio_mode", SETTING_WRITE, -1, HDIO_SET_PIO_MODE, TYPE_BYTE, 0, 255, 1, 1, NULL, set_pio_mode);
+ ide_add_setting(drive, "slow", SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->slow, NULL);
+ ide_add_setting(drive, "unmaskirq", drive->no_unmask ? SETTING_READ : SETTING_RW, HDIO_GET_UNMASKINTR, HDIO_SET_UNMASKINTR, TYPE_BYTE, 0, 1, 1, 1, &drive->unmask, NULL);
+ ide_add_setting(drive, "using_dma", SETTING_RW, HDIO_GET_DMA, HDIO_SET_DMA, TYPE_BYTE, 0, 1, 1, 1, &drive->using_dma, set_using_dma);
+}
+
+int ide_wait_cmd (ide_drive_t *drive, int cmd, int nsect, int feature, int sectors, byte *buf)
+{
+ struct request rq;
+ byte buffer[4];
+
+ if (!buf)
+ buf = buffer;
+ memset(buf, 0, 4 + SECTOR_WORDS * 4 * sectors);
+ ide_init_drive_cmd(&rq);
+ rq.buffer = buf;
+ *buf++ = cmd;
+ *buf++ = nsect;
+ *buf++ = feature;
+ *buf++ = sectors;
+ return ide_do_drive_cmd(drive, &rq, ide_wait);
+}
+
static int ide_ioctl (struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
int err, major, minor;
ide_drive_t *drive;
- unsigned long flags;
struct request rq;
kdev_t dev;
+ ide_settings_t *setting;
if (!inode || !(dev = inode->i_rdev))
return -EINVAL;
major = MAJOR(dev); minor = MINOR(dev);
if ((drive = get_info_ptr(inode->i_rdev)) == NULL)
return -ENODEV;
+
+ if ((setting = ide_find_setting_by_ioctl(drive, cmd)) != NULL) {
+ if (cmd == setting->read_ioctl) {
+ err = ide_read_setting(drive, setting);
+ return err >= 0 ? put_user(err, (long *) arg) : err;
+ } else {
+ if ((MINOR(inode->i_rdev) & PARTN_MASK))
+ return -EINVAL;
+ return ide_write_setting(drive, setting, arg);
+ }
+ }
+
ide_init_drive_cmd (&rq);
switch (cmd) {
case HDIO_GETGEO:
@@ -1729,54 +1964,13 @@ static int ide_ioctl (struct inode *inode, struct file *file,
invalidate_buffers(inode->i_rdev);
return 0;
- case BLKRASET:
- if (!suser()) return -EACCES;
- if(arg > 0xff) return -EINVAL;
- read_ahead[MAJOR(inode->i_rdev)] = arg;
- return 0;
-
- case BLKRAGET:
- return put_user(read_ahead[MAJOR(inode->i_rdev)], (long *) arg);
-
case BLKGETSIZE: /* Return device size */
return put_user(drive->part[MINOR(inode->i_rdev)&PARTN_MASK].nr_sects, (long *) arg);
- case BLKFRASET:
- if (!suser()) return -EACCES;
- max_readahead[major][minor] = arg;
- return 0;
-
- case BLKFRAGET:
- return put_user(max_readahead[major][minor], (long *) arg);
-
- case BLKSECTSET:
- if (!suser()) return -EACCES;
- if (!arg || arg > 0xff) return -EINVAL;
- max_sectors[major][minor] = arg;
- return 0;
-
- case BLKSECTGET:
- return put_user(max_sectors[major][minor], (long *) arg);
-
case BLKRRPART: /* Re-read partition tables */
if (!suser()) return -EACCES;
return ide_revalidate_disk(inode->i_rdev);
- case HDIO_GET_KEEPSETTINGS:
- return put_user(drive->keep_settings, (long *) arg);
-
- case HDIO_GET_UNMASKINTR:
- return put_user(drive->unmask, (long *) arg);
-
- case HDIO_GET_DMA:
- return put_user(drive->using_dma, (long *) arg);
-
- case HDIO_GET_32BIT:
- return put_user(drive->io_32bit, (long *) arg);
-
- case HDIO_GET_MULTCOUNT:
- return put_user(drive->mult_count, (long *) arg);
-
case HDIO_GET_IDENTITY:
if (MINOR(inode->i_rdev) & PARTN_MASK)
return -EINVAL;
@@ -1791,99 +1985,13 @@ static int ide_ioctl (struct inode *inode, struct file *file,
#endif
return 0;
- 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)
- return -EPERM;
- if (!drive->id || !(drive->id->capability & 1) || !HWIF(drive)->dmaproc)
- return -EPERM;
- case HDIO_SET_KEEPSETTINGS:
- case HDIO_SET_UNMASKINTR:
- case HDIO_SET_NOWERR:
- if (arg > 1)
- return -EINVAL;
- case HDIO_SET_32BIT:
- if (!suser()) return -EACCES;
- if ((MINOR(inode->i_rdev) & PARTN_MASK))
- return -EINVAL;
- save_flags(flags);
- cli();
- switch (cmd) {
- case HDIO_SET_DMA:
- if (!(HWIF(drive)->dmaproc)) {
- restore_flags(flags);
- return -EPERM;
- }
- 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;
- break;
- case HDIO_SET_UNMASKINTR:
- if (arg && drive->no_unmask) {
- restore_flags(flags);
- return -EPERM;
- }
- drive->unmask = arg;
- break;
- case HDIO_SET_NOWERR:
- drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT;
- break;
- case HDIO_SET_32BIT:
- if (arg > (1 + (SUPPORT_VLB_SYNC<<1))) {
- restore_flags(flags);
- return -EINVAL;
- }
- if (arg && drive->no_io_32bit) {
- restore_flags(flags);
- return -EPERM;
- }
- drive->io_32bit = arg;
-#ifdef CONFIG_BLK_DEV_DTC2278
- if (HWIF(drive)->chipset == ide_dtc2278)
- HWIF(drive)->drives[!drive->select.b.unit].io_32bit = arg;
-#endif /* CONFIG_BLK_DEV_DTC2278 */
- break;
- }
- restore_flags(flags);
- return 0;
-
- case HDIO_SET_MULTCOUNT:
- if (!suser()) return -EACCES;
- if (MINOR(inode->i_rdev) & PARTN_MASK)
- return -EINVAL;
- if (drive->id && arg > drive->id->max_multsect)
- return -EINVAL;
- save_flags(flags);
- cli();
- if (drive->special.b.set_multmode) {
- restore_flags(flags);
- return -EBUSY;
- }
- drive->mult_req = arg;
- drive->special.b.set_multmode = 1;
- restore_flags(flags);
- (void) ide_do_drive_cmd (drive, &rq, ide_wait);
- return (drive->mult_count == arg) ? 0 : -EIO;
-
+ return put_user(drive->dsc_overlap << IDE_NICE_DSC_OVERLAP |
+ drive->atapi_overlap << IDE_NICE_ATAPI_OVERLAP |
+ drive->nice0 << IDE_NICE_0 |
+ drive->nice1 << IDE_NICE_1 |
+ drive->nice2 << IDE_NICE_2,
+ (long *) arg);
case HDIO_DRIVE_CMD:
{
byte args[4], *argbuf = args;
@@ -1900,31 +2008,13 @@ static int ide_ioctl (struct inode *inode, struct file *file,
return -ENOMEM;
memcpy(argbuf, args, 4);
}
- rq.buffer = argbuf;
- err = ide_do_drive_cmd(drive, &rq, ide_wait);
+ err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf);
if (copy_to_user((void *)arg, argbuf, argsize))
err = -EFAULT;
if (argsize > 4)
kfree(argbuf);
return err;
}
- case HDIO_SET_PIO_MODE:
- if (!suser()) return -EACCES;
- if (MINOR(inode->i_rdev) & PARTN_MASK)
- return -EINVAL;
- if (!HWIF(drive)->tuneproc)
- return -ENOSYS;
- save_flags(flags);
- cli();
- if (drive->special.b.set_tune) {
- restore_flags(flags);
- return -EBUSY;
- }
- drive->tune_req = (byte) arg;
- drive->special.b.set_tune = 1;
- restore_flags(flags);
- (void) ide_do_drive_cmd (drive, &rq, ide_wait);
- return 0;
case HDIO_SCAN_HWIF:
{
@@ -2222,7 +2312,7 @@ __initfunc(void ide_setup (char *s))
if (i > 0 || i <= -7) { /* is parameter a chipset name? */
if (hwif->chipset != ide_unknown)
goto bad_option; /* chipset already specified */
- if (i != -7 && hw != 0)
+ if (i <= -7 && hw != 0)
goto bad_hwif; /* chipset drivers are for "ide0=" only */
if (ide_hwifs[hw^1].chipset != ide_unknown)
goto bad_option; /* chipset for 2nd port already specified */
@@ -2577,7 +2667,7 @@ static void setup_driver_defaults (ide_drive_t *drive)
if (d->special == NULL) d->special = default_special;
}
-ide_drive_t *ide_scan_devices (byte media, ide_driver_t *driver, int n)
+ide_drive_t *ide_scan_devices (byte media, const char *name, ide_driver_t *driver, int n)
{
unsigned int unit, index, i;
@@ -2587,31 +2677,39 @@ ide_drive_t *ide_scan_devices (byte media, ide_driver_t *driver, int n)
search:
for (index = 0, i = 0; index < MAX_HWIFS; ++index) {
ide_hwif_t *hwif = &ide_hwifs[index];
- if (hwif->present) {
- for (unit = 0; unit < MAX_DRIVES; ++unit) {
- ide_drive_t *drive = &hwif->drives[unit];
- if (drive->present && drive->media == media && drive->driver == driver && ++i > n)
- return drive;
- }
+ if (!hwif->present)
+ continue;
+ for (unit = 0; unit < MAX_DRIVES; ++unit) {
+ ide_drive_t *drive = &hwif->drives[unit];
+ char *req = drive->driver_req;
+ if (*req && !strstr(name, req))
+ continue;
+ if (drive->present && drive->media == media && drive->driver == driver && ++i > n)
+ return drive;
}
}
return NULL;
}
+static ide_proc_entry_t generic_subdriver_entries[] = {
+ { "capacity", proc_ide_read_capacity, NULL },
+ { NULL, NULL, NULL }
+};
+
int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int version)
{
unsigned long flags;
- save_flags(flags);
- cli();
+ __save_flags(flags);
+ __cli();
if (version != IDE_SUBDRIVER_VERSION || !drive->present || drive->driver != NULL ||
drive->busy || drive->usage) {
- restore_flags(flags);
+ __restore_flags(flags);
return 1;
}
drive->driver = driver;
setup_driver_defaults(drive);
- restore_flags(flags);
+ __restore_flags(flags);
if (drive->autotune != 2) {
if (driver->supports_dma && HWIF(drive)->dmaproc != NULL)
(void) (HWIF(drive)->dmaproc(ide_dma_check, drive));
@@ -2619,6 +2717,7 @@ int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int versio
drive->nice1 = 1;
}
drive->revalidate = 1;
+ ide_add_proc_entries(drive, generic_subdriver_entries);
ide_add_proc_entries(drive, driver->proc);
return 0;
}
@@ -2627,15 +2726,17 @@ int ide_unregister_subdriver (ide_drive_t *drive)
{
unsigned long flags;
- save_flags(flags);
- cli();
+ __save_flags(flags);
+ __cli();
if (drive->usage || drive->busy || drive->driver == NULL || DRIVER(drive)->busy) {
- restore_flags(flags);
+ __restore_flags(flags);
return 1;
}
ide_remove_proc_entries(drive, DRIVER(drive)->proc);
+ ide_remove_proc_entries(drive, generic_subdriver_entries);
+ auto_remove_settings(drive);
drive->driver = NULL;
- restore_flags(flags);
+ __restore_flags(flags);
return 0;
}
@@ -2692,6 +2793,7 @@ EXPORT_SYMBOL(ide_geninit);
EXPORT_SYMBOL(ide_fops);
EXPORT_SYMBOL(ide_get_queue);
EXPORT_SYMBOL(do_ide0_request);
+EXPORT_SYMBOL(ide_add_generic_settings);
#if MAX_HWIFS > 1
EXPORT_SYMBOL(do_ide1_request);
#endif /* MAX_HWIFS > 1 */
@@ -2724,9 +2826,12 @@ EXPORT_SYMBOL(ide_end_drive_cmd);
EXPORT_SYMBOL(ide_end_request);
EXPORT_SYMBOL(ide_revalidate_disk);
EXPORT_SYMBOL(ide_cmd);
+EXPORT_SYMBOL(ide_wait_cmd);
EXPORT_SYMBOL(ide_stall_queue);
EXPORT_SYMBOL(ide_add_proc_entries);
EXPORT_SYMBOL(ide_remove_proc_entries);
+EXPORT_SYMBOL(ide_add_setting);
+EXPORT_SYMBOL(ide_remove_setting);
EXPORT_SYMBOL(proc_ide_read_geometry);
EXPORT_SYMBOL(ide_register);