X-Git-Url: http://pilppa.org/gitweb/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fide%2Fide-probe.c;h=312127ea443afa6027c413fb6f8c5fb598afcbbe;hb=9b896033aa2781d36b2d3f756fe70325fc8487e2;hp=e953b70706c2a85fd7999e504828b3f469953999;hpb=b65fac32cfe3b2f98cd472fef400bd1c1340de23;p=linux-2.6-omap-h63xx.git diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index e953b70706c..312127ea443 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -189,7 +189,7 @@ static void ide_classify_atapi_dev(ide_drive_t *drive) static void do_identify(ide_drive_t *drive, u8 cmd) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; u16 *id = drive->id; char *m = (char *)&id[ATA_ID_PROD]; unsigned long flags; @@ -266,7 +266,7 @@ err_misc: static int actual_try_to_identify (ide_drive_t *drive, u8 cmd) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct ide_io_ports *io_ports = &hwif->io_ports; const struct ide_tp_ops *tp_ops = hwif->tp_ops; int use_altstatus = 0, rc; @@ -341,7 +341,7 @@ static int actual_try_to_identify (ide_drive_t *drive, u8 cmd) static int try_to_identify (ide_drive_t *drive, u8 cmd) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; const struct ide_tp_ops *tp_ops = hwif->tp_ops; int retval; int autoprobe = 0; @@ -438,7 +438,7 @@ static u8 ide_read_device(ide_drive_t *drive) static int do_probe (ide_drive_t *drive, u8 cmd) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; const struct ide_tp_ops *tp_ops = hwif->tp_ops; int rc; u8 present = !!(drive->dev_flags & IDE_DFLAG_PRESENT), stat; @@ -463,7 +463,7 @@ static int do_probe (ide_drive_t *drive, u8 cmd) if (ide_read_device(drive) != drive->select && present == 0) { if (drive->dn & 1) { /* exit with drive0 selected */ - SELECT_DRIVE(&hwif->drives[0]); + SELECT_DRIVE(hwif->devices[0]); /* allow ATA_BUSY to assert & clear */ msleep(50); } @@ -509,7 +509,7 @@ static int do_probe (ide_drive_t *drive, u8 cmd) } if (drive->dn & 1) { /* exit with drive0 selected */ - SELECT_DRIVE(&hwif->drives[0]); + SELECT_DRIVE(hwif->devices[0]); msleep(50); /* ensure drive irq is clear */ (void)tp_ops->read_status(hwif); @@ -522,7 +522,7 @@ static int do_probe (ide_drive_t *drive, u8 cmd) */ static void enable_nest (ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; const struct ide_tp_ops *tp_ops = hwif->tp_ops; u8 stat; @@ -697,7 +697,8 @@ out: static int ide_port_wait_ready(ide_hwif_t *hwif) { - int unit, rc; + ide_drive_t *drive; + int i, rc; printk(KERN_DEBUG "Probing IDE interface %s...\n", hwif->name); @@ -714,9 +715,7 @@ static int ide_port_wait_ready(ide_hwif_t *hwif) return rc; /* Now make sure both master & slave are ready */ - for (unit = 0; unit < MAX_DRIVES; unit++) { - ide_drive_t *drive = &hwif->drives[unit]; - + ide_port_for_each_dev(i, drive, hwif) { /* Ignore disks that we will not probe for later. */ if ((drive->dev_flags & IDE_DFLAG_NOPROBE) == 0 || (drive->dev_flags & IDE_DFLAG_PRESENT)) { @@ -732,8 +731,8 @@ static int ide_port_wait_ready(ide_hwif_t *hwif) } out: /* Exit function with master reselected (let's be sane) */ - if (unit) - SELECT_DRIVE(&hwif->drives[0]); + if (i) + SELECT_DRIVE(hwif->devices[0]); return rc; } @@ -749,7 +748,7 @@ out: void ide_undecoded_slave(ide_drive_t *dev1) { - ide_drive_t *dev0 = &dev1->hwif->drives[0]; + ide_drive_t *dev0 = dev1->hwif->devices[0]; if ((dev1->dn & 1) == 0 || (dev0->dev_flags & IDE_DFLAG_PRESENT) == 0) return; @@ -778,14 +777,15 @@ EXPORT_SYMBOL_GPL(ide_undecoded_slave); static int ide_probe_port(ide_hwif_t *hwif) { + ide_drive_t *drive; unsigned long flags; unsigned int irqd; - int unit, rc = -ENODEV; + int i, rc = -ENODEV; BUG_ON(hwif->present); - if ((hwif->drives[0].dev_flags & IDE_DFLAG_NOPROBE) && - (hwif->drives[1].dev_flags & IDE_DFLAG_NOPROBE)) + if ((hwif->devices[0]->dev_flags & IDE_DFLAG_NOPROBE) && + (hwif->devices[1]->dev_flags & IDE_DFLAG_NOPROBE)) return -EACCES; /* @@ -796,7 +796,8 @@ static int ide_probe_port(ide_hwif_t *hwif) if (irqd) disable_irq(hwif->irq); - local_irq_set(flags); + local_save_flags(flags); + local_irq_enable_in_hardirq(); if (ide_port_wait_ready(hwif) == -EBUSY) printk(KERN_DEBUG "%s: Wait for ready failed before probe !\n", hwif->name); @@ -805,9 +806,7 @@ static int ide_probe_port(ide_hwif_t *hwif) * Second drive should only exist if first drive was found, * but a lot of cdrom drives are configured as single slaves. */ - for (unit = 0; unit < MAX_DRIVES; ++unit) { - ide_drive_t *drive = &hwif->drives[unit]; - + ide_port_for_each_dev(i, drive, hwif) { (void) probe_for_drive(drive); if (drive->dev_flags & IDE_DFLAG_PRESENT) rc = 0; @@ -828,20 +827,17 @@ 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]; + ide_drive_t *drive; + int i; + ide_port_for_each_dev(i, drive, hwif) { if (drive->dev_flags & IDE_DFLAG_PRESENT) { if (port_ops && port_ops->quirkproc) port_ops->quirkproc(drive); } } - for (unit = 0; unit < MAX_DRIVES; ++unit) { - ide_drive_t *drive = &hwif->drives[unit]; - + ide_port_for_each_dev(i, drive, hwif) { if (drive->dev_flags & IDE_DFLAG_PRESENT) { ide_set_max_pio(drive); @@ -852,11 +848,8 @@ static void ide_port_tune_devices(ide_hwif_t *hwif) } } - for (unit = 0; unit < MAX_DRIVES; ++unit) { - ide_drive_t *drive = &hwif->drives[unit]; - - if ((hwif->host_flags & IDE_HFLAG_NO_IO_32BIT) || - drive->id[ATA_ID_DWORD_IO]) + ide_port_for_each_dev(i, drive, hwif) { + if (hwif->host_flags & IDE_HFLAG_NO_IO_32BIT) drive->dev_flags |= IDE_DFLAG_NO_IO_32BIT; else drive->dev_flags &= ~IDE_DFLAG_NO_IO_32BIT; @@ -869,7 +862,7 @@ static void ide_port_tune_devices(ide_hwif_t *hwif) static int ide_init_queue(ide_drive_t *drive) { struct request_queue *q; - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; int max_sectors = 256; int max_sg_entries = PRD_ENTRIES; @@ -918,18 +911,19 @@ static int ide_init_queue(ide_drive_t *drive) return 0; } +static DEFINE_MUTEX(ide_cfg_mtx); + /* * For any present drive: * - allocate the block device queue */ static int ide_port_setup_devices(ide_hwif_t *hwif) { + ide_drive_t *drive; int i, j = 0; mutex_lock(&ide_cfg_mtx); - for (i = 0; i < MAX_DRIVES; i++) { - ide_drive_t *drive = &hwif->drives[i]; - + ide_port_for_each_dev(i, drive, hwif) { if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0) continue; @@ -1014,7 +1008,7 @@ static struct kobject *ata_probe(dev_t dev, int *part, void *data) { ide_hwif_t *hwif = data; int unit = *part >> PARTN_BITS; - ide_drive_t *drive = &hwif->drives[unit]; + ide_drive_t *drive = hwif->devices[unit]; if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0) return NULL; @@ -1158,10 +1152,10 @@ out: static void hwif_register_devices(ide_hwif_t *hwif) { + ide_drive_t *drive; unsigned int i; - for (i = 0; i < MAX_DRIVES; i++) { - ide_drive_t *drive = &hwif->drives[i]; + ide_port_for_each_dev(i, drive, hwif) { struct device *dev = &drive->gendev; int ret; @@ -1184,11 +1178,10 @@ 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; + ide_drive_t *drive; int i; - for (i = 0; i < MAX_DRIVES; i++) { - ide_drive_t *drive = &hwif->drives[i]; - + ide_port_for_each_dev(i, drive, hwif) { drive->dn = i + hwif->channel * 2; if (hwif->host_flags & IDE_HFLAG_IO_32BIT) @@ -1236,6 +1229,8 @@ static void ide_init_port(ide_hwif_t *hwif, unsigned int port, if ((d->host_flags & IDE_HFLAG_NO_DMA) == 0) { int rc; + hwif->dma_ops = d->dma_ops; + if (d->init_dma) rc = d->init_dma(hwif, d); else @@ -1243,12 +1238,13 @@ static void ide_init_port(ide_hwif_t *hwif, unsigned int port, if (rc < 0) { printk(KERN_INFO "%s: DMA disabled\n", hwif->name); + + hwif->dma_ops = NULL; hwif->dma_base = 0; hwif->swdma_mask = 0; hwif->mwdma_mask = 0; hwif->ultra_mask = 0; - } else if (d->dma_ops) - hwif->dma_ops = d->dma_ops; + } } if ((d->host_flags & IDE_HFLAG_SERIALIZE) || @@ -1273,6 +1269,66 @@ static void ide_port_cable_detect(ide_hwif_t *hwif) } } +static const u8 ide_hwif_to_major[] = + { IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR, IDE4_MAJOR, + IDE5_MAJOR, IDE6_MAJOR, IDE7_MAJOR, IDE8_MAJOR, IDE9_MAJOR }; + +static void ide_port_init_devices_data(ide_hwif_t *hwif) +{ + ide_drive_t *drive; + int i; + + ide_port_for_each_dev(i, drive, hwif) { + u8 j = (hwif->index * MAX_DRIVES) + i; + + memset(drive, 0, sizeof(*drive)); + + drive->media = ide_disk; + drive->select = (i << 4) | ATA_DEVICE_OBS; + drive->hwif = hwif; + drive->ready_stat = ATA_DRDY; + drive->bad_wstat = BAD_W_STAT; + drive->special.b.recalibrate = 1; + drive->special.b.set_geometry = 1; + drive->name[0] = 'h'; + drive->name[1] = 'd'; + drive->name[2] = 'a' + j; + drive->max_failures = IDE_DEFAULT_MAX_FAILURES; + + INIT_LIST_HEAD(&drive->list); + init_completion(&drive->gendev_rel_comp); + } +} + +static void ide_init_port_data(ide_hwif_t *hwif, unsigned int index) +{ + /* fill in any non-zero initial values */ + hwif->index = index; + hwif->major = ide_hwif_to_major[index]; + + hwif->name[0] = 'i'; + hwif->name[1] = 'd'; + hwif->name[2] = 'e'; + hwif->name[3] = '0' + index; + + init_completion(&hwif->gendev_rel_comp); + + hwif->tp_ops = &default_tp_ops; + + ide_port_init_devices_data(hwif); +} + +static void ide_init_port_hw(ide_hwif_t *hwif, hw_regs_t *hw) +{ + memcpy(&hwif->io_ports, &hw->io_ports, sizeof(hwif->io_ports)); + hwif->irq = hw->irq; + hwif->chipset = hw->chipset; + hwif->dev = hw->dev; + hwif->gendev.parent = hw->parent ? hw->parent : hw->dev; + hwif->ack_intr = hw->ack_intr; + hwif->config_data = hw->config; +} + static unsigned int ide_indexes; /** @@ -1322,12 +1378,43 @@ static void ide_free_port_slot(int idx) mutex_unlock(&ide_cfg_mtx); } +static void ide_port_free_devices(ide_hwif_t *hwif) +{ + ide_drive_t *drive; + int i; + + ide_port_for_each_dev(i, drive, hwif) + kfree(drive); +} + +static int ide_port_alloc_devices(ide_hwif_t *hwif, int node) +{ + int i; + + for (i = 0; i < MAX_DRIVES; i++) { + ide_drive_t *drive; + + drive = kzalloc_node(sizeof(*drive), GFP_KERNEL, node); + if (drive == NULL) + goto out_nomem; + + hwif->devices[i] = drive; + } + return 0; + +out_nomem: + ide_port_free_devices(hwif); + return -ENOMEM; +} + struct ide_host *ide_host_alloc(const struct ide_port_info *d, hw_regs_t **hws) { struct ide_host *host; + struct device *dev = hws[0] ? hws[0]->dev : NULL; + int node = dev ? dev_to_node(dev) : -1; int i; - host = kzalloc(sizeof(*host), GFP_KERNEL); + host = kzalloc_node(sizeof(*host), GFP_KERNEL, node); if (host == NULL) return NULL; @@ -1338,10 +1425,15 @@ struct ide_host *ide_host_alloc(const struct ide_port_info *d, hw_regs_t **hws) if (hws[i] == NULL) continue; - hwif = kzalloc(sizeof(*hwif), GFP_KERNEL); + hwif = kzalloc_node(sizeof(*hwif), GFP_KERNEL, node); if (hwif == NULL) continue; + if (ide_port_alloc_devices(hwif, node) < 0) { + kfree(hwif); + continue; + } + idx = ide_find_port_slot(d); if (idx < 0) { printk(KERN_ERR "%s: no free slot for interface\n", @@ -1363,8 +1455,7 @@ struct ide_host *ide_host_alloc(const struct ide_port_info *d, hw_regs_t **hws) return NULL; } - if (hws[0]) - host->dev[0] = hws[0]->dev; + host->dev[0] = dev; if (d) { host->init_chipset = d->init_chipset; @@ -1381,9 +1472,7 @@ int ide_host_register(struct ide_host *host, const struct ide_port_info *d, ide_hwif_t *hwif, *mate = NULL; int i, j = 0; - for (i = 0; i < MAX_HOST_PORTS; i++) { - hwif = host->ports[i]; - + ide_host_for_each_port(i, hwif, host) { if (hwif == NULL) { mate = NULL; continue; @@ -1409,9 +1498,7 @@ int ide_host_register(struct ide_host *host, const struct ide_port_info *d, ide_port_init_devices(hwif); } - for (i = 0; i < MAX_HOST_PORTS; i++) { - hwif = host->ports[i]; - + ide_host_for_each_port(i, hwif, host) { if (hwif == NULL) continue; @@ -1426,9 +1513,7 @@ int ide_host_register(struct ide_host *host, const struct ide_port_info *d, ide_port_tune_devices(hwif); } - for (i = 0; i < MAX_HOST_PORTS; i++) { - hwif = host->ports[i]; - + ide_host_for_each_port(i, hwif, host) { if (hwif == NULL) continue; @@ -1453,9 +1538,7 @@ int ide_host_register(struct ide_host *host, const struct ide_port_info *d, ide_acpi_port_init_devices(hwif); } - for (i = 0; i < MAX_HOST_PORTS; i++) { - hwif = host->ports[i]; - + ide_host_for_each_port(i, hwif, host) { if (hwif == NULL) continue; @@ -1463,9 +1546,7 @@ int ide_host_register(struct ide_host *host, const struct ide_port_info *d, hwif_register_devices(hwif); } - for (i = 0; i < MAX_HOST_PORTS; i++) { - hwif = host->ports[i]; - + ide_host_for_each_port(i, hwif, host) { if (hwif == NULL) continue; @@ -1503,17 +1584,85 @@ int ide_host_add(const struct ide_port_info *d, hw_regs_t **hws, } EXPORT_SYMBOL_GPL(ide_host_add); +static void __ide_port_unregister_devices(ide_hwif_t *hwif) +{ + ide_drive_t *drive; + int i; + + ide_port_for_each_dev(i, drive, hwif) { + if (drive->dev_flags & IDE_DFLAG_PRESENT) { + device_unregister(&drive->gendev); + wait_for_completion(&drive->gendev_rel_comp); + } + } +} + +void ide_port_unregister_devices(ide_hwif_t *hwif) +{ + mutex_lock(&ide_cfg_mtx); + __ide_port_unregister_devices(hwif); + hwif->present = 0; + ide_port_init_devices_data(hwif); + mutex_unlock(&ide_cfg_mtx); +} +EXPORT_SYMBOL_GPL(ide_port_unregister_devices); + +/** + * ide_unregister - free an IDE interface + * @hwif: IDE interface + * + * Perform the final unregister of an IDE interface. + * + * Locking: + * The caller must not hold the IDE locks. + * + * It is up to the caller to be sure there is no pending I/O here, + * and that the interface will not be reopened (present/vanishing + * locking isn't yet done BTW). + */ + +static void ide_unregister(ide_hwif_t *hwif) +{ + BUG_ON(in_interrupt()); + BUG_ON(irqs_disabled()); + + mutex_lock(&ide_cfg_mtx); + + if (hwif->present) { + __ide_port_unregister_devices(hwif); + hwif->present = 0; + } + + ide_proc_unregister_port(hwif); + + free_irq(hwif->irq, hwif); + + device_unregister(hwif->portdev); + device_unregister(&hwif->gendev); + wait_for_completion(&hwif->gendev_rel_comp); + + /* + * Remove us from the kernel's knowledge + */ + blk_unregister_region(MKDEV(hwif->major, 0), MAX_DRIVES<sg_table); + unregister_blkdev(hwif->major, hwif->name); + + ide_release_dma_engine(hwif); + + mutex_unlock(&ide_cfg_mtx); +} + void ide_host_free(struct ide_host *host) { ide_hwif_t *hwif; int i; - for (i = 0; i < MAX_HOST_PORTS; i++) { - hwif = host->ports[i]; - + ide_host_for_each_port(i, hwif, host) { if (hwif == NULL) continue; + ide_port_free_devices(hwif); ide_free_port_slot(hwif->index); kfree(hwif); } @@ -1524,11 +1673,12 @@ EXPORT_SYMBOL_GPL(ide_host_free); void ide_host_remove(struct ide_host *host) { + ide_hwif_t *hwif; int i; - for (i = 0; i < MAX_HOST_PORTS; i++) { - if (host->ports[i]) - ide_unregister(host->ports[i]); + ide_host_for_each_port(i, hwif, host) { + if (hwif) + ide_unregister(hwif); } ide_host_free(host); @@ -1547,8 +1697,8 @@ void ide_port_scan(ide_hwif_t *hwif) hwif->present = 1; ide_port_tune_devices(hwif); - ide_acpi_port_init_devices(hwif); ide_port_setup_devices(hwif); + ide_acpi_port_init_devices(hwif); hwif_register_devices(hwif); ide_proc_port_register_devices(hwif); }