Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
[safe/jmp/linux-2.6] / drivers / ide / ide-probe.c
index 84a8956..70aa86c 100644 (file)
@@ -39,8 +39,6 @@
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
-static ide_hwif_t ide_hwifs[MAX_HWIFS]; /* master data repository */
-
 /**
  *     generic_id              -       add a generic drive id
  *     @drive: drive to make an ID block for
@@ -136,18 +134,6 @@ static inline void do_identify (ide_drive_t *drive, u8 cmd)
 #endif
        ide_fix_driveid(id);
 
-#if defined (CONFIG_SCSI_EATA_PIO) || defined (CONFIG_SCSI_EATA)
-       /*
-        * EATA SCSI controllers do a hardware ATA emulation:
-        * Ignore them if there is a driver for them available.
-        */
-       if ((id->model[0] == 'P' && id->model[1] == 'M') ||
-           (id->model[0] == 'S' && id->model[1] == 'K')) {
-               printk("%s: EATA SCSI HBA %.10s\n", drive->name, id->model);
-               goto err_misc;
-       }
-#endif /* CONFIG_SCSI_EATA || CONFIG_SCSI_EATA_PIO */
-
        /*
         *  WIN_IDENTIFY returns little-endian info,
         *  WIN_PIDENTIFY *usually* returns little-endian info.
@@ -169,7 +155,8 @@ static inline void do_identify (ide_drive_t *drive, u8 cmd)
        if (strstr(id->model, "E X A B Y T E N E S T"))
                goto err_misc;
 
-       printk("%s: %s, ", drive->name, id->model);
+       printk(KERN_INFO "%s: %s, ", drive->name, id->model);
+
        drive->present = 1;
        drive->dead = 0;
 
@@ -178,16 +165,17 @@ static inline void do_identify (ide_drive_t *drive, u8 cmd)
         */
        if (cmd == WIN_PIDENTIFY) {
                u8 type = (id->config >> 8) & 0x1f;
-               printk("ATAPI ");
+
+               printk(KERN_CONT "ATAPI ");
                switch (type) {
                        case ide_floppy:
                                if (!strstr(id->model, "CD-ROM")) {
                                        if (!strstr(id->model, "oppy") &&
                                            !strstr(id->model, "poyp") &&
                                            !strstr(id->model, "ZIP"))
-                                               printk("cdrom or floppy?, assuming ");
+                                               printk(KERN_CONT "cdrom or floppy?, assuming ");
                                        if (drive->media != ide_cdrom) {
-                                               printk ("FLOPPY");
+                                               printk(KERN_CONT "FLOPPY");
                                                drive->removable = 1;
                                                break;
                                        }
@@ -200,25 +188,25 @@ static inline void do_identify (ide_drive_t *drive, u8 cmd)
                                /* kludge for Apple PowerBook internal zip */
                                if (!strstr(id->model, "CD-ROM") &&
                                    strstr(id->model, "ZIP")) {
-                                       printk ("FLOPPY");
+                                       printk(KERN_CONT "FLOPPY");
                                        type = ide_floppy;
                                        break;
                                }
 #endif
-                               printk ("CD/DVD-ROM");
+                               printk(KERN_CONT "CD/DVD-ROM");
                                break;
                        case ide_tape:
-                               printk ("TAPE");
+                               printk(KERN_CONT "TAPE");
                                break;
                        case ide_optical:
-                               printk ("OPTICAL");
+                               printk(KERN_CONT "OPTICAL");
                                drive->removable = 1;
                                break;
                        default:
-                               printk("UNKNOWN (type %d)", type);
+                               printk(KERN_CONT "UNKNOWN (type %d)", type);
                                break;
                }
-               printk (" drive\n");
+               printk(KERN_CONT " drive\n");
                drive->media = type;
                /* an ATAPI device ignores DRDY */
                drive->ready_stat = 0;
@@ -238,7 +226,9 @@ static inline void do_identify (ide_drive_t *drive, u8 cmd)
                drive->removable = 1;
 
        drive->media = ide_disk;
-       printk("%s DISK drive\n", (id->config == 0x848a) ? "CFA" : "ATA" );
+
+       printk(KERN_CONT "%s DISK drive\n",
+               (id->config == 0x848a) ? "CFA" : "ATA");
 
        return;
 
@@ -389,7 +379,7 @@ static int try_to_identify (ide_drive_t *drive, u8 cmd)
                                /* Mmmm.. multiple IRQs..
                                 * don't know which was ours
                                 */
-                               printk("%s: IRQ probe failed (0x%lx)\n",
+                               printk(KERN_ERR "%s: IRQ probe failed (0x%lx)\n",
                                        drive->name, cookie);
                        }
                }
@@ -458,7 +448,7 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
                        return 4;
        }
 #ifdef DEBUG
-       printk("probing for %s: present=%d, media=%d, probetype=%s\n",
+       printk(KERN_INFO "probing for %s: present=%d, media=%d, probetype=%s\n",
                drive->name, drive->present, drive->media,
                (cmd == WIN_IDENTIFY) ? "ATA" : "ATAPI");
 #endif
@@ -536,7 +526,8 @@ static void enable_nest (ide_drive_t *drive)
        const struct ide_tp_ops *tp_ops = hwif->tp_ops;
        u8 stat;
 
-       printk("%s: enabling %s -- ", hwif->name, drive->id->model);
+       printk(KERN_INFO "%s: enabling %s -- ", hwif->name, drive->id->model);
+
        SELECT_DRIVE(drive);
        msleep(50);
        tp_ops->exec_command(hwif, EXABYTE_ENABLE_NEST);
@@ -640,7 +631,7 @@ static inline u8 probe_for_drive (ide_drive_t *drive)
        return drive->present;
 }
 
-static void hwif_release_dev (struct device *dev)
+static void hwif_release_dev(struct device *dev)
 {
        ide_hwif_t *hwif = container_of(dev, ide_hwif_t, gendev);
 
@@ -885,7 +876,7 @@ static void save_match(ide_hwif_t *hwif, ide_hwif_t *new, ide_hwif_t **match)
        if (m && m->hwgroup && m->hwgroup != new->hwgroup) {
                if (!new->hwgroup)
                        return;
-               printk("%s: potential irq problem with %s and %s\n",
+               printk(KERN_WARNING "%s: potential IRQ problem with %s and %s\n",
                        hwif->name, new->name, m->name);
        }
        if (!m || m->irq != hwif->irq) /* don't undo a prior perfect match */
@@ -992,6 +983,45 @@ static void ide_port_setup_devices(ide_hwif_t *hwif)
        mutex_unlock(&ide_cfg_mtx);
 }
 
+static ide_hwif_t *ide_ports[MAX_HWIFS];
+
+void ide_remove_port_from_hwgroup(ide_hwif_t *hwif)
+{
+       ide_hwgroup_t *hwgroup = hwif->hwgroup;
+
+       ide_ports[hwif->index] = NULL;
+
+       spin_lock_irq(&ide_lock);
+       /*
+        * Remove us from the hwgroup, and free
+        * the hwgroup if we were the only member
+        */
+       if (hwif->next == hwif) {
+               BUG_ON(hwgroup->hwif != hwif);
+               kfree(hwgroup);
+       } else {
+               /* There is another interface in hwgroup.
+                * Unlink us, and set hwgroup->drive and ->hwif to
+                * something sane.
+                */
+               ide_hwif_t *g = hwgroup->hwif;
+
+               while (g->next != hwif)
+                       g = g->next;
+               g->next = hwif->next;
+               if (hwgroup->hwif == hwif) {
+                       /* Chose a random hwif for hwgroup->hwif.
+                        * It's guaranteed that there are no drives
+                        * left in the hwgroup.
+                        */
+                       BUG_ON(hwgroup->drive != NULL);
+                       hwgroup->hwif = g;
+               }
+               BUG_ON(hwgroup->hwif == hwif);
+       }
+       spin_unlock_irq(&ide_lock);
+}
+
 /*
  * This routine sets up the irq for an ide interface, and creates a new
  * hwgroup for the irq/hwif if none was previously assigned.
@@ -1019,8 +1049,9 @@ static int init_irq (ide_hwif_t *hwif)
         * Group up with any other hwifs that share our irq(s).
         */
        for (index = 0; index < MAX_HWIFS; index++) {
-               ide_hwif_t *h = &ide_hwifs[index];
-               if (h->hwgroup) {  /* scan only initialized hwif's */
+               ide_hwif_t *h = ide_ports[index];
+
+               if (h && h->hwgroup) {  /* scan only initialized ports */
                        if (hwif->irq == h->irq) {
                                hwif->sharing_irq = h->sharing_irq = 1;
                                if (hwif->chipset != ide_pci ||
@@ -1074,6 +1105,8 @@ static int init_irq (ide_hwif_t *hwif)
                hwgroup->timer.data = (unsigned long) hwgroup;
        }
 
+       ide_ports[hwif->index] = hwif;
+
        /*
         * Allocate the irq, if not already obtained for another hwif
         */
@@ -1102,17 +1135,17 @@ static int init_irq (ide_hwif_t *hwif)
        }
 
 #if !defined(__mc68000__)
-       printk("%s at 0x%03lx-0x%03lx,0x%03lx on irq %d", hwif->name,
+       printk(KERN_INFO "%s at 0x%03lx-0x%03lx,0x%03lx on irq %d", hwif->name,
                io_ports->data_addr, io_ports->status_addr,
                io_ports->ctl_addr, hwif->irq);
 #else
-       printk("%s at 0x%08lx on irq %d", hwif->name,
+       printk(KERN_INFO "%s at 0x%08lx on irq %d", hwif->name,
                io_ports->data_addr, hwif->irq);
 #endif /* __mc68000__ */
        if (match)
-               printk(" (%sed with %s)",
+               printk(KERN_CONT " (%sed with %s)",
                        hwif->sharing_irq ? "shar" : "serializ", match->name);
-       printk("\n");
+       printk(KERN_CONT "\n");
 
        mutex_unlock(&ide_cfg_mtx);
        return 0;
@@ -1155,7 +1188,7 @@ static struct kobject *exact_match(dev_t dev, int *part, void *data)
 {
        struct gendisk *p = data;
        *part &= (1 << PARTN_BITS) - 1;
-       return &p->dev.kobj;
+       return &disk_to_dev(p)->kobj;
 }
 
 static int exact_lock(dev_t dev, void *data)
@@ -1247,7 +1280,7 @@ static int hwif_init(ide_hwif_t *hwif)
        if (!hwif->irq) {
                hwif->irq = __ide_default_irq(hwif->io_ports.data_addr);
                if (!hwif->irq) {
-                       printk("%s: DISABLED, NO IRQ\n", hwif->name);
+                       printk(KERN_ERR "%s: disabled, no IRQ\n", hwif->name);
                        return 0;
                }
        }
@@ -1277,16 +1310,16 @@ static int hwif_init(ide_hwif_t *hwif)
         */
        hwif->irq = __ide_default_irq(hwif->io_ports.data_addr);
        if (!hwif->irq) {
-               printk("%s: Disabled unable to get IRQ %d.\n",
+               printk(KERN_ERR "%s: disabled, unable to get IRQ %d\n",
                        hwif->name, old_irq);
                goto out;
        }
        if (init_irq(hwif)) {
-               printk("%s: probed IRQ %d and default IRQ %d failed.\n",
+               printk(KERN_ERR "%s: probed IRQ %d and default IRQ %d failed\n",
                        hwif->name, old_irq, hwif->irq);
                goto out;
        }
-       printk("%s: probed IRQ %d failed, using default.\n",
+       printk(KERN_WARNING "%s: probed IRQ %d failed, using default\n",
                hwif->name, hwif->irq);
 
 done:
@@ -1459,7 +1492,7 @@ static struct device_attribute *ide_port_attrs[] = {
 
 static int ide_sysfs_register_port(ide_hwif_t *hwif)
 {
-       int i, rc;
+       int i, uninitialized_var(rc);
 
        for (i = 0; ide_port_attrs[i]; i++) {
                rc = device_create_file(hwif->portdev, ide_port_attrs[i]);
@@ -1470,18 +1503,20 @@ static int ide_sysfs_register_port(ide_hwif_t *hwif)
        return rc;
 }
 
+static unsigned int ide_indexes;
+
 /**
- *     ide_find_port_slot      -       find free ide_hwifs[] slot
+ *     ide_find_port_slot      -       find free port slot
  *     @d: IDE port info
  *
- *     Return the new hwif.  If we are out of free slots return NULL.
+ *     Return the new port slot index or -ENOENT if we are out of free slots.
  */
 
-static ide_hwif_t *ide_find_port_slot(const struct ide_port_info *d)
+static int ide_find_port_slot(const struct ide_port_info *d)
 {
-       ide_hwif_t *hwif;
-       int i;
+       int idx = -ENOENT;
        u8 bootable = (d && (d->host_flags & IDE_HFLAG_NON_BOOTABLE)) ? 0 : 1;
+       u8 i = (d && (d->host_flags & IDE_HFLAG_QD_2ND_PORT)) ? 1 : 0;;
 
        /*
         * Claim an unassigned slot.
@@ -1493,35 +1528,33 @@ static ide_hwif_t *ide_find_port_slot(const struct ide_port_info *d)
         * 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)
-                               goto out_found;
-               }
+       mutex_lock(&ide_cfg_mtx);
+       if (MAX_HWIFS == 1) {
+               if (ide_indexes == 0 && i == 0)
+                       idx = 1;
        } else {
-               for (i = 2; i < MAX_HWIFS; i++) {
-                       hwif = &ide_hwifs[i];
-                       if (hwif->chipset == ide_unknown)
-                               goto out_found;
-               }
-               for (i = 0; i < 2 && i < MAX_HWIFS; i++) {
-                       hwif = &ide_hwifs[i];
-                       if (hwif->chipset == ide_unknown)
-                               goto out_found;
+               if (bootable) {
+                       if ((ide_indexes | i) != (1 << MAX_HWIFS) - 1)
+                               idx = ffz(ide_indexes | i);
+               } else {
+                       if ((ide_indexes | 3) != (1 << MAX_HWIFS) - 1)
+                               idx = ffz(ide_indexes | 3);
+                       else if ((ide_indexes & 3) != 3)
+                               idx = ffz(ide_indexes);
                }
        }
+       if (idx >= 0)
+               ide_indexes |= (1 << idx);
+       mutex_unlock(&ide_cfg_mtx);
 
-       printk(KERN_ERR "%s: no free slot for interface\n",
-                       d ? d->name : "ide");
-
-       return NULL;
+       return idx;
+}
 
-out_found:
-       ide_init_port_data(hwif, i);
-       return hwif;
+static void ide_free_port_slot(int idx)
+{
+       mutex_lock(&ide_cfg_mtx);
+       ide_indexes &= ~(1 << idx);
+       mutex_unlock(&ide_cfg_mtx);
 }
 
 struct ide_host *ide_host_alloc_all(const struct ide_port_info *d,
@@ -1536,17 +1569,29 @@ struct ide_host *ide_host_alloc_all(const struct ide_port_info *d,
 
        for (i = 0; i < MAX_HWIFS; i++) {
                ide_hwif_t *hwif;
+               int idx;
 
                if (hws[i] == NULL)
                        continue;
 
-               hwif = ide_find_port_slot(d);
-               if (hwif) {
-                       hwif->chipset = hws[i]->chipset;
+               hwif = kzalloc(sizeof(*hwif), GFP_KERNEL);
+               if (hwif == NULL)
+                       continue;
 
-                       host->ports[i] = hwif;
-                       host->n_ports++;
+               idx = ide_find_port_slot(d);
+               if (idx < 0) {
+                       printk(KERN_ERR "%s: no free slot for interface\n",
+                                       d ? d->name : "ide");
+                       kfree(hwif);
+                       continue;
                }
+
+               ide_init_port_data(hwif, idx);
+
+               hwif->host = host;
+
+               host->ports[i] = hwif;
+               host->n_ports++;
        }
 
        if (host->n_ports == 0) {
@@ -1554,6 +1599,12 @@ struct ide_host *ide_host_alloc_all(const struct ide_port_info *d,
                return NULL;
        }
 
+       if (hws[0])
+               host->dev[0] = hws[0]->dev;
+
+       if (d)
+               host->host_flags = d->host_flags;
+
        return host;
 }
 EXPORT_SYMBOL_GPL(ide_host_alloc_all);
@@ -1574,19 +1625,16 @@ int ide_host_register(struct ide_host *host, const struct ide_port_info *d,
                      hw_regs_t **hws)
 {
        ide_hwif_t *hwif, *mate = NULL;
-       u8 idx[MAX_HWIFS];
-       int i, rc = 0;
+       int i, j = 0;
 
        for (i = 0; i < MAX_HWIFS; i++) {
-               idx[i] = host->ports[i] ? host->ports[i]->index : 0xff;
+               hwif = host->ports[i];
 
-               if (idx[i] == 0xff) {
+               if (hwif == NULL) {
                        mate = NULL;
                        continue;
                }
 
-               hwif = &ide_hwifs[idx[i]];
-
                ide_init_port_hw(hwif, hws[i]);
                ide_port_apply_params(hwif);
 
@@ -1608,10 +1656,10 @@ int ide_host_register(struct ide_host *host, const struct ide_port_info *d,
        }
 
        for (i = 0; i < MAX_HWIFS; i++) {
-               if (idx[i] == 0xff)
-                       continue;
+               hwif = host->ports[i];
 
-               hwif = &ide_hwifs[idx[i]];
+               if (hwif == NULL)
+                       continue;
 
                if (ide_probe_port(hwif) == 0)
                        hwif->present = 1;
@@ -1625,19 +1673,20 @@ int ide_host_register(struct ide_host *host, const struct ide_port_info *d,
        }
 
        for (i = 0; i < MAX_HWIFS; i++) {
-               if (idx[i] == 0xff)
-                       continue;
+               hwif = host->ports[i];
 
-               hwif = &ide_hwifs[idx[i]];
+               if (hwif == NULL)
+                       continue;
 
                if (hwif_init(hwif) == 0) {
                        printk(KERN_INFO "%s: failed to initialize IDE "
                                         "interface\n", hwif->name);
                        hwif->present = 0;
-                       rc = -1;
                        continue;
                }
 
+               j++;
+
                if (hwif->present)
                        ide_port_setup_devices(hwif);
 
@@ -1648,10 +1697,10 @@ int ide_host_register(struct ide_host *host, const struct ide_port_info *d,
        }
 
        for (i = 0; i < MAX_HWIFS; i++) {
-               if (idx[i] == 0xff)
-                       continue;
+               hwif = host->ports[i];
 
-               hwif = &ide_hwifs[idx[i]];
+               if (hwif == NULL)
+                       continue;
 
                if (hwif->chipset == ide_unknown)
                        hwif->chipset = ide_generic;
@@ -1661,10 +1710,10 @@ int ide_host_register(struct ide_host *host, const struct ide_port_info *d,
        }
 
        for (i = 0; i < MAX_HWIFS; i++) {
-               if (idx[i] == 0xff)
-                       continue;
+               hwif = host->ports[i];
 
-               hwif = &ide_hwifs[idx[i]];
+               if (hwif == NULL)
+                       continue;
 
                ide_sysfs_register_port(hwif);
                ide_proc_register_port(hwif);
@@ -1673,10 +1722,52 @@ int ide_host_register(struct ide_host *host, const struct ide_port_info *d,
                        ide_proc_port_register_devices(hwif);
        }
 
-       return rc;
+       return j ? 0 : -1;
 }
 EXPORT_SYMBOL_GPL(ide_host_register);
 
+int ide_host_add(const struct ide_port_info *d, hw_regs_t **hws,
+                struct ide_host **hostp)
+{
+       struct ide_host *host;
+       int rc;
+
+       host = ide_host_alloc(d, hws);
+       if (host == NULL)
+               return -ENOMEM;
+
+       rc = ide_host_register(host, d, hws);
+       if (rc) {
+               ide_host_free(host);
+               return rc;
+       }
+
+       if (hostp)
+               *hostp = host;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ide_host_add);
+
+void ide_host_free(struct ide_host *host)
+{
+       ide_hwif_t *hwif;
+       int i;
+
+       for (i = 0; i < MAX_HWIFS; i++) {
+               hwif = host->ports[i];
+
+               if (hwif == NULL)
+                       continue;
+
+               ide_free_port_slot(hwif->index);
+               kfree(hwif);
+       }
+
+       kfree(host);
+}
+EXPORT_SYMBOL_GPL(ide_host_free);
+
 void ide_host_remove(struct ide_host *host)
 {
        int i;
@@ -1686,7 +1777,7 @@ void ide_host_remove(struct ide_host *host)
                        ide_unregister(host->ports[i]);
        }
 
-       kfree(host);
+       ide_host_free(host);
 }
 EXPORT_SYMBOL_GPL(ide_host_remove);
 
@@ -1749,7 +1840,6 @@ static void ide_legacy_init_one(hw_regs_t **hws, hw_regs_t *hw,
 
 int ide_legacy_device_add(const struct ide_port_info *d, unsigned long config)
 {
-       struct ide_host *host;
        hw_regs_t hw[2], *hws[] = { NULL, NULL, NULL, NULL };
 
        memset(&hw, 0, sizeof(hw));
@@ -1762,12 +1852,6 @@ int ide_legacy_device_add(const struct ide_port_info *d, unsigned long config)
            (d->host_flags & IDE_HFLAG_SINGLE))
                return -ENOENT;
 
-       host = ide_host_alloc(d, hws);
-       if (host == NULL)
-               return -ENOMEM;
-
-       ide_host_register(host, d, hws);
-
-       return 0;
+       return ide_host_add(d, hws, NULL);
 }
 EXPORT_SYMBOL_GPL(ide_legacy_device_add);