diff options
author | Paul Mundt <lethal@linux-sh.org> | 2008-10-20 11:17:52 +0900 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2008-10-20 11:17:52 +0900 |
commit | 4cb40f795af36b3deb743f6ccf6c3fd542c61c8d (patch) | |
tree | db3d7519932549bf528f5b8e4cb8350356cd544d /drivers/ide/ide.c | |
parent | 79ed2a9216dd3cc35c4f2c5dbaddadb195af83ac (diff) | |
parent | 0cfd81031a26717fe14380d18275f8e217571615 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Conflicts:
Documentation/kernel-parameters.txt
arch/sh/include/asm/elf.h
Diffstat (limited to 'drivers/ide/ide.c')
-rw-r--r-- | drivers/ide/ide.c | 351 |
1 files changed, 103 insertions, 248 deletions
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 772451600e4..04f8f13cb9d 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -44,8 +44,6 @@ * inspiration from lots of linux users, esp. hamish@zot.apana.org.au */ -#define _IDE_C /* Tell ide.h it's really us */ - #include <linux/module.h> #include <linux/types.h> #include <linux/string.h> @@ -58,6 +56,7 @@ #include <linux/init.h> #include <linux/pci.h> #include <linux/ide.h> +#include <linux/hdreg.h> #include <linux/completion.h> #include <linux/device.h> @@ -97,8 +96,6 @@ void ide_init_port_data(ide_hwif_t *hwif, unsigned int index) hwif->name[2] = 'e'; hwif->name[3] = '0' + index; - hwif->bus_state = BUSSTATE_ON; - init_completion(&hwif->gendev_rel_comp); hwif->tp_ops = &default_tp_ops; @@ -117,9 +114,9 @@ static void ide_port_init_devices_data(ide_hwif_t *hwif) memset(drive, 0, sizeof(*drive)); drive->media = ide_disk; - drive->select.all = (unit<<4)|0xa0; + drive->select = (unit << 4) | ATA_DEVICE_OBS; drive->hwif = hwif; - drive->ready_stat = READY_STAT; + drive->ready_stat = ATA_DRDY; drive->bad_wstat = BAD_W_STAT; drive->special.b.recalibrate = 1; drive->special.b.set_geometry = 1; @@ -141,7 +138,7 @@ static void __ide_port_unregister_devices(ide_hwif_t *hwif) for (i = 0; i < MAX_DRIVES; i++) { ide_drive_t *drive = &hwif->drives[i]; - if (drive->present) { + if (drive->dev_flags & IDE_DFLAG_PRESENT) { spin_unlock_irq(&ide_lock); device_unregister(&drive->gendev); wait_for_completion(&drive->gendev_rel_comp); @@ -230,8 +227,7 @@ void ide_unregister(ide_hwif_t *hwif) kfree(hwif->sg_table); unregister_blkdev(hwif->major, hwif->name); - if (hwif->dma_base) - ide_release_dma_engine(hwif); + ide_release_dma_engine(hwif); mutex_unlock(&ide_cfg_mtx); } @@ -253,96 +249,52 @@ void ide_init_port_hw(ide_hwif_t *hwif, hw_regs_t *hw) DEFINE_MUTEX(ide_setting_mtx); -EXPORT_SYMBOL_GPL(ide_setting_mtx); - -/** - * ide_spin_wait_hwgroup - wait for group - * @drive: drive in the group - * - * Wait for an IDE device group to go non busy and then return - * holding the ide_lock which guards the hwgroup->busy status - * and right to use it. - */ - -int ide_spin_wait_hwgroup (ide_drive_t *drive) -{ - ide_hwgroup_t *hwgroup = HWGROUP(drive); - unsigned long timeout = jiffies + (3 * HZ); - - spin_lock_irq(&ide_lock); +ide_devset_get(io_32bit, io_32bit); - while (hwgroup->busy) { - unsigned long lflags; - spin_unlock_irq(&ide_lock); - local_irq_set(lflags); - if (time_after(jiffies, timeout)) { - local_irq_restore(lflags); - printk(KERN_ERR "%s: channel busy\n", drive->name); - return -EBUSY; - } - local_irq_restore(lflags); - spin_lock_irq(&ide_lock); - } - return 0; -} - -EXPORT_SYMBOL(ide_spin_wait_hwgroup); - -int set_io_32bit(ide_drive_t *drive, int arg) +static int set_io_32bit(ide_drive_t *drive, int arg) { - if (drive->no_io_32bit) + if (drive->dev_flags & IDE_DFLAG_NO_IO_32BIT) return -EPERM; if (arg < 0 || arg > 1 + (SUPPORT_VLB_SYNC << 1)) return -EINVAL; - if (ide_spin_wait_hwgroup(drive)) - return -EBUSY; - drive->io_32bit = arg; - spin_unlock_irq(&ide_lock); - return 0; } +ide_devset_get_flag(ksettings, IDE_DFLAG_KEEP_SETTINGS); + static int set_ksettings(ide_drive_t *drive, int arg) { if (arg < 0 || arg > 1) return -EINVAL; - if (ide_spin_wait_hwgroup(drive)) - return -EBUSY; - drive->keep_settings = arg; - spin_unlock_irq(&ide_lock); + if (arg) + drive->dev_flags |= IDE_DFLAG_KEEP_SETTINGS; + else + drive->dev_flags &= ~IDE_DFLAG_KEEP_SETTINGS; return 0; } -int set_using_dma(ide_drive_t *drive, int arg) +ide_devset_get_flag(using_dma, IDE_DFLAG_USING_DMA); + +static int set_using_dma(ide_drive_t *drive, int arg) { #ifdef CONFIG_BLK_DEV_IDEDMA - ide_hwif_t *hwif = drive->hwif; int err = -EPERM; if (arg < 0 || arg > 1) return -EINVAL; - if (!drive->id || !(drive->id->capability & 1)) + if (ata_id_has_dma(drive->id) == 0) goto out; - if (hwif->dma_ops == NULL) + if (drive->hwif->dma_ops == NULL) goto out; - err = -EBUSY; - if (ide_spin_wait_hwgroup(drive)) - goto out; - /* - * set ->busy flag, unlock and let it ride - */ - hwif->hwgroup->busy = 1; - spin_unlock_irq(&ide_lock); - err = 0; if (arg) { @@ -351,12 +303,6 @@ int set_using_dma(ide_drive_t *drive, int arg) } else ide_dma_off(drive); - /* - * lock, clear ->busy flag and unlock before leaving - */ - spin_lock_irq(&ide_lock); - hwif->hwgroup->busy = 0; - spin_unlock_irq(&ide_lock); out: return err; #else @@ -367,9 +313,32 @@ out: #endif } -int set_pio_mode(ide_drive_t *drive, int arg) +/* + * handle HDIO_SET_PIO_MODE ioctl abusers here, eventually it will go away + */ +static int set_pio_mode_abuse(ide_hwif_t *hwif, u8 req_pio) +{ + switch (req_pio) { + case 202: + case 201: + case 200: + case 102: + case 101: + case 100: + return (hwif->host_flags & IDE_HFLAG_ABUSE_DMA_MODES) ? 1 : 0; + case 9: + case 8: + return (hwif->host_flags & IDE_HFLAG_ABUSE_PREFETCH) ? 1 : 0; + case 7: + case 6: + return (hwif->host_flags & IDE_HFLAG_ABUSE_FAST_DEVSEL) ? 1 : 0; + default: + return 0; + } +} + +static int set_pio_mode(ide_drive_t *drive, int arg) { - struct request *rq; ide_hwif_t *hwif = drive->hwif; const struct ide_port_ops *port_ops = hwif->port_ops; @@ -380,48 +349,65 @@ int set_pio_mode(ide_drive_t *drive, int arg) (hwif->host_flags & IDE_HFLAG_NO_SET_MODE)) return -ENOSYS; - if (drive->special.b.set_tune) - return -EBUSY; + if (set_pio_mode_abuse(drive->hwif, arg)) { + if (arg == 8 || arg == 9) { + unsigned long flags; - rq = blk_get_request(drive->queue, READ, __GFP_WAIT); - rq->cmd_type = REQ_TYPE_ATA_TASKFILE; + /* take lock for IDE_DFLAG_[NO_]UNMASK/[NO_]IO_32BIT */ + spin_lock_irqsave(&ide_lock, flags); + port_ops->set_pio_mode(drive, arg); + spin_unlock_irqrestore(&ide_lock, flags); + } else + port_ops->set_pio_mode(drive, arg); + } else { + int keep_dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA); - drive->tune_req = (u8) arg; - drive->special.b.set_tune = 1; + ide_set_pio(drive, arg); - blk_execute_rq(drive->queue, NULL, rq, 0); - blk_put_request(rq); + if (hwif->host_flags & IDE_HFLAG_SET_PIO_MODE_KEEP_DMA) { + if (keep_dma) + ide_dma_on(drive); + } + } return 0; } +ide_devset_get_flag(unmaskirq, IDE_DFLAG_UNMASK); + static int set_unmaskirq(ide_drive_t *drive, int arg) { - if (drive->no_unmask) + if (drive->dev_flags & IDE_DFLAG_NO_UNMASK) return -EPERM; if (arg < 0 || arg > 1) return -EINVAL; - if (ide_spin_wait_hwgroup(drive)) - return -EBUSY; - drive->unmask = arg; - spin_unlock_irq(&ide_lock); + if (arg) + drive->dev_flags |= IDE_DFLAG_UNMASK; + else + drive->dev_flags &= ~IDE_DFLAG_UNMASK; return 0; } +ide_ext_devset_rw_sync(io_32bit, io_32bit); +ide_ext_devset_rw_sync(keepsettings, ksettings); +ide_ext_devset_rw_sync(unmaskirq, unmaskirq); +ide_ext_devset_rw_sync(using_dma, using_dma); +__IDE_DEVSET(pio_mode, DS_SYNC, NULL, set_pio_mode); + static int generic_ide_suspend(struct device *dev, pm_message_t mesg) { - ide_drive_t *drive = dev->driver_data; + ide_drive_t *drive = dev->driver_data, *pair = ide_get_pair_dev(drive); ide_hwif_t *hwif = HWIF(drive); struct request *rq; struct request_pm_state rqpm; ide_task_t args; int ret; - /* Call ACPI _GTM only once */ - if (!(drive->dn % 2)) + /* call ACPI _GTM only once */ + if ((drive->dn & 1) == 0 || pair == NULL) ide_acpi_get_timing(hwif); memset(&rqpm, 0, sizeof(rqpm)); @@ -430,33 +416,32 @@ static int generic_ide_suspend(struct device *dev, pm_message_t mesg) rq->cmd_type = REQ_TYPE_PM_SUSPEND; rq->special = &args; rq->data = &rqpm; - rqpm.pm_step = ide_pm_state_start_suspend; + rqpm.pm_step = IDE_PM_START_SUSPEND; if (mesg.event == PM_EVENT_PRETHAW) mesg.event = PM_EVENT_FREEZE; rqpm.pm_state = mesg.event; ret = blk_execute_rq(drive->queue, NULL, rq, 0); blk_put_request(rq); - /* only call ACPI _PS3 after both drivers are suspended */ - if (!ret && (((drive->dn % 2) && hwif->drives[0].present - && hwif->drives[1].present) - || !hwif->drives[0].present - || !hwif->drives[1].present)) + + /* call ACPI _PS3 only after both devices are suspended */ + if (ret == 0 && ((drive->dn & 1) || pair == NULL)) ide_acpi_set_state(hwif, 0); + return ret; } static int generic_ide_resume(struct device *dev) { - ide_drive_t *drive = dev->driver_data; + ide_drive_t *drive = dev->driver_data, *pair = ide_get_pair_dev(drive); ide_hwif_t *hwif = HWIF(drive); struct request *rq; struct request_pm_state rqpm; ide_task_t args; int err; - /* Call ACPI _STM only once */ - if (!(drive->dn % 2)) { + /* call ACPI _PS0 / _STM only once */ + if ((drive->dn & 1) == 0 || pair == NULL) { ide_acpi_set_state(hwif, 1); ide_acpi_push_timing(hwif); } @@ -470,7 +455,7 @@ static int generic_ide_resume(struct device *dev) rq->cmd_flags |= REQ_PREEMPT; rq->special = &args; rq->data = &rqpm; - rqpm.pm_step = ide_pm_state_start_resume; + rqpm.pm_step = IDE_PM_START_RESUME; rqpm.pm_state = PM_EVENT_ON; err = blk_execute_rq(drive->queue, NULL, rq, 1); @@ -486,138 +471,6 @@ static int generic_ide_resume(struct device *dev) return err; } -static int generic_drive_reset(ide_drive_t *drive) -{ - struct request *rq; - int ret = 0; - - rq = blk_get_request(drive->queue, READ, __GFP_WAIT); - rq->cmd_type = REQ_TYPE_SPECIAL; - rq->cmd_len = 1; - rq->cmd[0] = REQ_DRIVE_RESET; - rq->cmd_flags |= REQ_SOFTBARRIER; - if (blk_execute_rq(drive->queue, NULL, rq, 1)) - ret = rq->errors; - blk_put_request(rq); - return ret; -} - -int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device *bdev, - unsigned int cmd, unsigned long arg) -{ - unsigned long flags; - ide_driver_t *drv; - void __user *p = (void __user *)arg; - int err = 0, (*setfunc)(ide_drive_t *, int); - u8 *val; - - switch (cmd) { - case HDIO_GET_32BIT: val = &drive->io_32bit; goto read_val; - case HDIO_GET_KEEPSETTINGS: val = &drive->keep_settings; goto read_val; - case HDIO_GET_UNMASKINTR: val = &drive->unmask; goto read_val; - case HDIO_GET_DMA: val = &drive->using_dma; goto read_val; - case HDIO_SET_32BIT: setfunc = set_io_32bit; goto set_val; - case HDIO_SET_KEEPSETTINGS: setfunc = set_ksettings; goto set_val; - case HDIO_SET_PIO_MODE: setfunc = set_pio_mode; goto set_val; - case HDIO_SET_UNMASKINTR: setfunc = set_unmaskirq; goto set_val; - case HDIO_SET_DMA: setfunc = set_using_dma; goto set_val; - } - - switch (cmd) { - case HDIO_OBSOLETE_IDENTITY: - case HDIO_GET_IDENTITY: - if (bdev != bdev->bd_contains) - return -EINVAL; - if (drive->id_read == 0) - return -ENOMSG; - if (copy_to_user(p, drive->id, (cmd == HDIO_GET_IDENTITY) ? sizeof(*drive->id) : 142)) - return -EFAULT; - return 0; - - case HDIO_GET_NICE: - return put_user(drive->dsc_overlap << IDE_NICE_DSC_OVERLAP | - drive->atapi_overlap << IDE_NICE_ATAPI_OVERLAP | - drive->nice1 << IDE_NICE_1, - (long __user *) arg); -#ifdef CONFIG_IDE_TASK_IOCTL - case HDIO_DRIVE_TASKFILE: - if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) - return -EACCES; - switch(drive->media) { - case ide_disk: - return ide_taskfile_ioctl(drive, cmd, arg); - default: - return -ENOMSG; - } -#endif /* CONFIG_IDE_TASK_IOCTL */ - - case HDIO_DRIVE_CMD: - if (!capable(CAP_SYS_RAWIO)) - return -EACCES; - return ide_cmd_ioctl(drive, cmd, arg); - - case HDIO_DRIVE_TASK: - if (!capable(CAP_SYS_RAWIO)) - return -EACCES; - return ide_task_ioctl(drive, cmd, arg); - case HDIO_SET_NICE: - if (!capable(CAP_SYS_ADMIN)) return -EACCES; - if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP) | (1 << IDE_NICE_1)))) - return -EPERM; - drive->dsc_overlap = (arg >> IDE_NICE_DSC_OVERLAP) & 1; - drv = *(ide_driver_t **)bdev->bd_disk->private_data; - if (drive->dsc_overlap && !drv->supports_dsc_overlap) { - drive->dsc_overlap = 0; - return -EPERM; - } - drive->nice1 = (arg >> IDE_NICE_1) & 1; - return 0; - case HDIO_DRIVE_RESET: - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - - return generic_drive_reset(drive); - - case HDIO_GET_BUSSTATE: - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - if (put_user(HWIF(drive)->bus_state, (long __user *)arg)) - return -EFAULT; - return 0; - - case HDIO_SET_BUSSTATE: - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - return -EOPNOTSUPP; - default: - return -EINVAL; - } - -read_val: - mutex_lock(&ide_setting_mtx); - spin_lock_irqsave(&ide_lock, flags); - err = *val; - spin_unlock_irqrestore(&ide_lock, flags); - mutex_unlock(&ide_setting_mtx); - return err >= 0 ? put_user(err, (long __user *)arg) : err; - -set_val: - if (bdev != bdev->bd_contains) - err = -EINVAL; - else { - if (!capable(CAP_SYS_ADMIN)) - err = -EACCES; - else { - mutex_lock(&ide_setting_mtx); - err = setfunc(drive, arg); - mutex_unlock(&ide_setting_mtx); - } - } - return err; -} - -EXPORT_SYMBOL(generic_ide_ioctl); - /** * ide_device_get - get an additional reference to a ide_drive_t * @drive: device to get a reference to @@ -710,21 +563,21 @@ static ssize_t model_show(struct device *dev, struct device_attribute *attr, char *buf) { ide_drive_t *drive = to_ide_device(dev); - return sprintf(buf, "%s\n", drive->id->model); + return sprintf(buf, "%s\n", (char *)&drive->id[ATA_ID_PROD]); } static ssize_t firmware_show(struct device *dev, struct device_attribute *attr, char *buf) { ide_drive_t *drive = to_ide_device(dev); - return sprintf(buf, "%s\n", drive->id->fw_rev); + return sprintf(buf, "%s\n", (char *)&drive->id[ATA_ID_FW_REV]); } static ssize_t serial_show(struct device *dev, struct device_attribute *attr, char *buf) { ide_drive_t *drive = to_ide_device(dev); - return sprintf(buf, "%s\n", drive->id->serial_no); + return sprintf(buf, "%s\n", (char *)&drive->id[ATA_ID_SERNO]); } static struct device_attribute ide_dev_attrs[] = { @@ -734,6 +587,7 @@ static struct device_attribute ide_dev_attrs[] = { __ATTR_RO(model), __ATTR_RO(firmware), __ATTR(serial, 0400, serial_show, NULL), + __ATTR(unload_heads, 0644, ide_park_show, ide_park_store), __ATTR_NULL }; @@ -841,7 +695,7 @@ MODULE_PARM_DESC(noprobe, "skip probing for a device"); static unsigned int ide_nowerr; module_param_call(nowerr, ide_set_dev_param_mask, NULL, &ide_nowerr, 0); -MODULE_PARM_DESC(nowerr, "ignore the WRERR_STAT bit for a device"); +MODULE_PARM_DESC(nowerr, "ignore the ATA_DF bit for a device"); static unsigned int ide_cdroms; @@ -888,31 +742,31 @@ static int ide_set_disk_chs(const char *str, struct kernel_param *kp) module_param_call(chs, ide_set_disk_chs, NULL, NULL, 0); MODULE_PARM_DESC(chs, "force device as a disk (using CHS)"); -static void ide_dev_apply_params(ide_drive_t *drive) +static void ide_dev_apply_params(ide_drive_t *drive, u8 unit) { - int i = drive->hwif->index * MAX_DRIVES + drive->select.b.unit; + int i = drive->hwif->index * MAX_DRIVES + unit; if (ide_nodma & (1 << i)) { printk(KERN_INFO "ide: disallowing DMA for %s\n", drive->name); - drive->nodma = 1; + drive->dev_flags |= IDE_DFLAG_NODMA; } if (ide_noflush & (1 << i)) { printk(KERN_INFO "ide: disabling flush requests for %s\n", drive->name); - drive->noflush = 1; + drive->dev_flags |= IDE_DFLAG_NOFLUSH; } if (ide_noprobe & (1 << i)) { printk(KERN_INFO "ide: skipping probe for %s\n", drive->name); - drive->noprobe = 1; + drive->dev_flags |= IDE_DFLAG_NOPROBE; } if (ide_nowerr & (1 << i)) { - printk(KERN_INFO "ide: ignoring the WRERR_STAT bit for %s\n", + printk(KERN_INFO "ide: ignoring the ATA_DF bit for %s\n", drive->name); drive->bad_wstat = BAD_R_STAT; } if (ide_cdroms & (1 << i)) { printk(KERN_INFO "ide: forcing %s as a CD-ROM\n", drive->name); - drive->present = 1; + drive->dev_flags |= IDE_DFLAG_PRESENT; drive->media = ide_cdrom; /* an ATAPI device ignores DRDY */ drive->ready_stat = 0; @@ -921,13 +775,14 @@ static void ide_dev_apply_params(ide_drive_t *drive) drive->cyl = drive->bios_cyl = ide_disks_chs[i].cyl; drive->head = drive->bios_head = ide_disks_chs[i].head; drive->sect = drive->bios_sect = ide_disks_chs[i].sect; - drive->forced_geom = 1; + printk(KERN_INFO "ide: forcing %s as a disk (%d/%d/%d)\n", drive->name, drive->cyl, drive->head, drive->sect); - drive->present = 1; + + drive->dev_flags |= IDE_DFLAG_FORCED_GEOM | IDE_DFLAG_PRESENT; drive->media = ide_disk; - drive->ready_stat = READY_STAT; + drive->ready_stat = ATA_DRDY; } } @@ -965,7 +820,7 @@ void ide_port_apply_params(ide_hwif_t *hwif) } for (i = 0; i < MAX_DRIVES; i++) - ide_dev_apply_params(&hwif->drives[i]); + ide_dev_apply_params(&hwif->drives[i], i); } /* |