X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fide%2Fide-probe.c;h=d2faef17e548bdcd1fbc1f6062700862e14bcf4d;hb=8d9f9a76ea09911f4aaf0d9e852fd25335080f53;hp=194ecb0049eb1ed37c3dde4c00d3a83273c1dc88;hpb=99642e211a789df34347c3f10f0301462837f0c5;p=linux-2.6 diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 194ecb0049..d2faef17e5 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -271,7 +271,7 @@ static int actual_try_to_identify (ide_drive_t *drive, u8 cmd) /* take a deep breath */ msleep(50); - if (IDE_CONTROL_REG) { + if (hwif->io_ports[IDE_CONTROL_OFFSET]) { a = ide_read_altstatus(drive); s = ide_read_status(drive); if ((a ^ s) & ~INDEX_STAT) @@ -289,10 +289,10 @@ static int actual_try_to_identify (ide_drive_t *drive, u8 cmd) */ if ((cmd == WIN_PIDENTIFY)) /* disable dma & overlap */ - hwif->OUTB(0, IDE_FEATURE_REG); + hwif->OUTB(0, hwif->io_ports[IDE_FEATURE_OFFSET]); /* ask drive for ID */ - hwif->OUTB(cmd, IDE_COMMAND_REG); + hwif->OUTB(cmd, hwif->io_ports[IDE_COMMAND_OFFSET]); timeout = ((cmd == WIN_IDENTIFY) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2; timeout += jiffies; @@ -353,7 +353,7 @@ static int try_to_identify (ide_drive_t *drive, u8 cmd) * interrupts during the identify-phase that * the irq handler isn't expecting. */ - if (IDE_CONTROL_REG) { + if (hwif->io_ports[IDE_CONTROL_OFFSET]) { if (!hwif->irq) { autoprobe = 1; cookie = probe_irq_on(); @@ -445,7 +445,8 @@ static int do_probe (ide_drive_t *drive, u8 cmd) msleep(50); SELECT_DRIVE(drive); msleep(50); - if (hwif->INB(IDE_SELECT_REG) != drive->select.all && !drive->present) { + if (hwif->INB(hwif->io_ports[IDE_SELECT_OFFSET]) != drive->select.all && + !drive->present) { if (drive->select.b.unit != 0) { /* exit with drive0 selected */ SELECT_DRIVE(&hwif->drives[0]); @@ -477,9 +478,11 @@ static int do_probe (ide_drive_t *drive, u8 cmd) printk(KERN_ERR "%s: no response (status = 0x%02x), " "resetting drive\n", drive->name, stat); msleep(50); - hwif->OUTB(drive->select.all, IDE_SELECT_REG); + hwif->OUTB(drive->select.all, + hwif->io_ports[IDE_SELECT_OFFSET]); msleep(50); - hwif->OUTB(WIN_SRST, IDE_COMMAND_REG); + hwif->OUTB(WIN_SRST, + hwif->io_ports[IDE_COMMAND_OFFSET]); (void)ide_busy_sleep(hwif); rc = try_to_identify(drive, cmd); } @@ -515,7 +518,7 @@ static void enable_nest (ide_drive_t *drive) printk("%s: enabling %s -- ", hwif->name, drive->id->model); SELECT_DRIVE(drive); msleep(50); - hwif->OUTB(EXABYTE_ENABLE_NEST, IDE_COMMAND_REG); + hwif->OUTB(EXABYTE_ENABLE_NEST, hwif->io_ports[IDE_COMMAND_OFFSET]); if (ide_busy_sleep(hwif)) { printk(KERN_CONT "failed (timeout)\n"); @@ -623,7 +626,7 @@ static void hwif_release_dev (struct device *dev) complete(&hwif->gendev_rel_comp); } -static void ide_register_port(ide_hwif_t *hwif) +static int ide_register_port(ide_hwif_t *hwif) { int ret; @@ -639,9 +642,23 @@ static void ide_register_port(ide_hwif_t *hwif) } hwif->gendev.release = hwif_release_dev; ret = device_register(&hwif->gendev); - if (ret < 0) + if (ret < 0) { printk(KERN_WARNING "IDE: %s: device_register error: %d\n", - __FUNCTION__, ret); + __func__, ret); + goto out; + } + + get_device(&hwif->gendev); + + hwif->portdev = device_create(ide_port_class, &hwif->gendev, + MKDEV(0, 0), hwif->name); + if (IS_ERR(hwif->portdev)) { + ret = PTR_ERR(hwif->portdev); + device_unregister(&hwif->gendev); + } + dev_set_drvdata(hwif->portdev, hwif); +out: + return ret; } /** @@ -756,8 +773,7 @@ static int ide_probe_port(ide_hwif_t *hwif) BUG_ON(hwif->present); - if (hwif->noprobe || - (hwif->drives[0].noprobe && hwif->drives[1].noprobe)) + if (hwif->drives[0].noprobe && hwif->drives[1].noprobe) return -EACCES; /* @@ -774,9 +790,10 @@ static int ide_probe_port(ide_hwif_t *hwif) printk(KERN_DEBUG "%s: Wait for ready failed before probe !\n", hwif->name); /* - * Need to probe slave device first to make it release PDIAG-. + * Second drive should only exist if first drive was found, + * but a lot of cdrom drives are configured as single slaves. */ - for (unit = MAX_DRIVES - 1; unit >= 0; unit--) { + for (unit = 0; unit < MAX_DRIVES; ++unit) { ide_drive_t *drive = &hwif->drives[unit]; drive->dn = (hwif->channel ? 2 : 0) + unit; (void) probe_for_drive(drive); @@ -803,13 +820,14 @@ static int ide_probe_port(ide_hwif_t *hwif) static void ide_port_tune_devices(ide_hwif_t *hwif) { + const struct ide_port_ops *port_ops = hwif->port_ops; int unit; for (unit = 0; unit < MAX_DRIVES; unit++) { ide_drive_t *drive = &hwif->drives[unit]; - if (drive->present && hwif->quirkproc) - hwif->quirkproc(drive); + if (drive->present && port_ops && port_ops->quirkproc) + port_ops->quirkproc(drive); } for (unit = 0; unit < MAX_DRIVES; ++unit) { @@ -948,6 +966,7 @@ static void ide_port_setup_devices(ide_hwif_t *hwif) { int i; + mutex_lock(&ide_cfg_mtx); for (i = 0; i < MAX_DRIVES; i++) { ide_drive_t *drive = &hwif->drives[i]; @@ -962,6 +981,7 @@ static void ide_port_setup_devices(ide_hwif_t *hwif) ide_add_drive_to_hwgroup(drive); } + mutex_unlock(&ide_cfg_mtx); } /* @@ -1087,8 +1107,6 @@ static int init_irq (ide_hwif_t *hwif) hwif->sharing_irq ? "shar" : "serializ", match->name); printk("\n"); - ide_port_setup_devices(hwif); - mutex_unlock(&ide_cfg_mtx); return 0; out_unlink: @@ -1198,6 +1216,8 @@ static void drive_release_dev (struct device *dev) { ide_drive_t *drive = container_of(dev, ide_drive_t, gendev); + ide_proc_unregister_device(drive); + spin_lock_irq(&ide_lock); ide_remove_drive_from_hwgroup(drive); kfree(drive->id); @@ -1213,6 +1233,10 @@ static void drive_release_dev (struct device *dev) complete(&drive->gendev_rel_comp); } +#ifndef ide_default_irq +#define ide_default_irq(irq) 0 +#endif + static int hwif_init(ide_hwif_t *hwif) { int old_irq; @@ -1224,13 +1248,6 @@ static int hwif_init(ide_hwif_t *hwif) return 0; } } -#ifdef CONFIG_BLK_DEV_HD - if (hwif->irq == HD_IRQ && hwif->io_ports[IDE_DATA_OFFSET] != HD_DATA) { - printk("%s: CANNOT SHARE IRQ WITH OLD " - "HARDDISK DRIVER (hd.c)\n", hwif->name); - return 0; - } -#endif /* CONFIG_BLK_DEV_HD */ if (register_blkdev(hwif->major, hwif->name)) return 0; @@ -1307,6 +1324,7 @@ static void hwif_register_devices(ide_hwif_t *hwif) static void ide_port_init_devices(ide_hwif_t *hwif) { + const struct ide_port_ops *port_ops = hwif->port_ops; int i; for (i = 0; i < MAX_DRIVES; i++) { @@ -1322,8 +1340,8 @@ static void ide_port_init_devices(ide_hwif_t *hwif) drive->autotune = 1; } - if (hwif->port_init_devs) - hwif->port_init_devs(hwif); + if (port_ops && port_ops->port_init_devs) + port_ops->port_init_devs(hwif); } static void ide_init_port(ide_hwif_t *hwif, unsigned int port, @@ -1348,6 +1366,10 @@ static void ide_init_port(ide_hwif_t *hwif, unsigned int port, hwif->host_flags = d->host_flags; hwif->pio_mask = d->pio_mask; + /* ->set_pio_mode for DTC2278 is currently limited to port 0 */ + if (hwif->chipset != ide_dtc2278 || hwif->channel == 0) + hwif->port_ops = d->port_ops; + if ((d->host_flags & IDE_HFLAG_SERIALIZE) && hwif->mate) hwif->mate->serialized = hwif->serialized = 1; @@ -1365,12 +1387,117 @@ static void ide_init_port(ide_hwif_t *hwif, unsigned int port, /* call chipset specific routine for each enabled port */ if (d->init_hwif) d->init_hwif(hwif); +} - if (hwif->cable_detect && (hwif->ultra_mask & 0x78)) { +static void ide_port_cable_detect(ide_hwif_t *hwif) +{ + const struct ide_port_ops *port_ops = hwif->port_ops; + + if (port_ops && port_ops->cable_detect && (hwif->ultra_mask & 0x78)) { if (hwif->cbl != ATA_CBL_PATA40_SHORT) - hwif->cbl = hwif->cable_detect(hwif); + hwif->cbl = port_ops->cable_detect(hwif); + } +} + +static ssize_t store_delete_devices(struct device *portdev, + struct device_attribute *attr, + const char *buf, size_t n) +{ + ide_hwif_t *hwif = dev_get_drvdata(portdev); + + if (strncmp(buf, "1", n)) + return -EINVAL; + + ide_port_unregister_devices(hwif); + + return n; +}; + +static DEVICE_ATTR(delete_devices, S_IWUSR, NULL, store_delete_devices); + +static ssize_t store_scan(struct device *portdev, + struct device_attribute *attr, + const char *buf, size_t n) +{ + ide_hwif_t *hwif = dev_get_drvdata(portdev); + + if (strncmp(buf, "1", n)) + return -EINVAL; + + ide_port_unregister_devices(hwif); + ide_port_scan(hwif); + + return n; +}; + +static DEVICE_ATTR(scan, S_IWUSR, NULL, store_scan); + +static struct device_attribute *ide_port_attrs[] = { + &dev_attr_delete_devices, + &dev_attr_scan, + NULL +}; + +static int ide_sysfs_register_port(ide_hwif_t *hwif) +{ + int i, rc; + + for (i = 0; ide_port_attrs[i]; i++) { + rc = device_create_file(hwif->portdev, ide_port_attrs[i]); + if (rc) + break; + } + + return rc; +} + +/** + * ide_find_port_slot - find free ide_hwifs[] slot + * @d: IDE port info + * + * Return the new hwif. If we are out of free slots return NULL. + */ + +ide_hwif_t *ide_find_port_slot(const struct ide_port_info *d) +{ + ide_hwif_t *hwif; + int i; + u8 bootable = (d && (d->host_flags & IDE_HFLAG_NON_BOOTABLE)) ? 0 : 1; + + /* + * Claim an unassigned slot. + * + * Give preference to claiming other slots before claiming ide0/ide1, + * just in case there's another interface yet-to-be-scanned + * which uses ports 0x1f0/0x170 (the ide0/ide1 defaults). + * + * Unless there is a bootable card that does not use the standard + * ports 0x1f0/0x170 (the ide0/ide1 defaults). + */ + if (bootable) { + i = (d && (d->host_flags & IDE_HFLAG_QD_2ND_PORT)) ? 1 : 0; + + for (; i < MAX_HWIFS; i++) { + hwif = &ide_hwifs[i]; + if (hwif->chipset == ide_unknown) + return hwif; + } + } else { + for (i = 2; i < MAX_HWIFS; i++) { + hwif = &ide_hwifs[i]; + if (hwif->chipset == ide_unknown) + return hwif; + } + for (i = 0; i < 2 && i < MAX_HWIFS; i++) { + hwif = &ide_hwifs[i]; + if (hwif->chipset == ide_unknown) + return hwif; + } } + + return NULL; } +EXPORT_SYMBOL_GPL(ide_find_port_slot); int ide_device_add_all(u8 *idx, const struct ide_port_info *d) { @@ -1393,6 +1520,7 @@ int ide_device_add_all(u8 *idx, const struct ide_port_info *d) mate = (i & 1) ? NULL : hwif; ide_init_port(hwif, i & 1, d); + ide_port_cable_detect(hwif); ide_port_init_devices(hwif); } @@ -1402,25 +1530,15 @@ int ide_device_add_all(u8 *idx, const struct ide_port_info *d) hwif = &ide_hwifs[idx[i]]; - if ((hwif->chipset != ide_4drives || !hwif->mate || - !hwif->mate->present) && ide_hwif_request_regions(hwif)) { - printk(KERN_ERR "%s: ports already in use, " - "skipping probe\n", hwif->name); - continue; - } - - if (ide_probe_port(hwif) < 0) { - ide_hwif_release_regions(hwif); - continue; - } - - hwif->present = 1; + if (ide_probe_port(hwif) == 0) + hwif->present = 1; if (hwif->chipset != ide_4drives || !hwif->mate || !hwif->mate->present) ide_register_port(hwif); - ide_port_tune_devices(hwif); + if (hwif->present) + ide_port_tune_devices(hwif); } for (i = 0; i < MAX_HWIFS; i++) { @@ -1429,9 +1547,6 @@ int ide_device_add_all(u8 *idx, const struct ide_port_info *d) hwif = &ide_hwifs[idx[i]]; - if (!hwif->present) - continue; - if (hwif_init(hwif) == 0) { printk(KERN_INFO "%s: failed to initialize IDE " "interface\n", hwif->name); @@ -1440,8 +1555,13 @@ int ide_device_add_all(u8 *idx, const struct ide_port_info *d) continue; } + if (hwif->present) + ide_port_setup_devices(hwif); + ide_acpi_init(hwif); - ide_acpi_port_init_devices(hwif); + + if (hwif->present) + ide_acpi_port_init_devices(hwif); } for (i = 0; i < MAX_HWIFS; i++) { @@ -1450,12 +1570,11 @@ int ide_device_add_all(u8 *idx, const struct ide_port_info *d) hwif = &ide_hwifs[idx[i]]; - if (hwif->present) { - if (hwif->chipset == ide_unknown || - hwif->chipset == ide_forced) - hwif->chipset = ide_generic; + if (hwif->chipset == ide_unknown) + hwif->chipset = ide_generic; + + if (hwif->present) hwif_register_devices(hwif); - } } for (i = 0; i < MAX_HWIFS; i++) { @@ -1464,10 +1583,11 @@ int ide_device_add_all(u8 *idx, const struct ide_port_info *d) hwif = &ide_hwifs[idx[i]]; - if (hwif->present) { - ide_proc_register_port(hwif); + ide_sysfs_register_port(hwif); + ide_proc_register_port(hwif); + + if (hwif->present) ide_proc_port_register_devices(hwif); - } } return rc; @@ -1485,3 +1605,85 @@ int ide_device_add(u8 idx[4], const struct ide_port_info *d) return ide_device_add_all(idx_all, d); } EXPORT_SYMBOL_GPL(ide_device_add); + +void ide_port_scan(ide_hwif_t *hwif) +{ + ide_port_cable_detect(hwif); + ide_port_init_devices(hwif); + + if (ide_probe_port(hwif) < 0) + return; + + hwif->present = 1; + + ide_port_tune_devices(hwif); + ide_acpi_port_init_devices(hwif); + ide_port_setup_devices(hwif); + hwif_register_devices(hwif); + ide_proc_port_register_devices(hwif); +} +EXPORT_SYMBOL_GPL(ide_port_scan); + +static void ide_legacy_init_one(u8 *idx, hw_regs_t *hw, u8 port_no, + const struct ide_port_info *d, + unsigned long config) +{ + ide_hwif_t *hwif; + unsigned long base, ctl; + int irq; + + if (port_no == 0) { + base = 0x1f0; + ctl = 0x3f6; + irq = 14; + } else { + base = 0x170; + ctl = 0x376; + irq = 15; + } + + if (!request_region(base, 8, d->name)) { + printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n", + d->name, base, base + 7); + return; + } + + if (!request_region(ctl, 1, d->name)) { + printk(KERN_ERR "%s: I/O resource 0x%lX not free.\n", + d->name, ctl); + release_region(base, 8); + return; + } + + ide_std_init_ports(hw, base, ctl); + hw->irq = irq; + + hwif = ide_find_port_slot(d); + if (hwif) { + ide_init_port_hw(hwif, hw); + if (config) + hwif->config_data = config; + idx[port_no] = hwif->index; + } +} + +int ide_legacy_device_add(const struct ide_port_info *d, unsigned long config) +{ + u8 idx[4] = { 0xff, 0xff, 0xff, 0xff }; + hw_regs_t hw[2]; + + memset(&hw, 0, sizeof(hw)); + + if ((d->host_flags & IDE_HFLAG_QD_2ND_PORT) == 0) + ide_legacy_init_one(idx, &hw[0], 0, d, config); + ide_legacy_init_one(idx, &hw[1], 1, d, config); + + if (idx[0] == 0xff && idx[1] == 0xff && + (d->host_flags & IDE_HFLAG_SINGLE)) + return -ENOENT; + + ide_device_add(idx, d); + + return 0; +} +EXPORT_SYMBOL_GPL(ide_legacy_device_add);