fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / ide / ide-probe.c
index 4ffaf90..5a5c565 100644 (file)
@@ -33,7 +33,6 @@
 
 #undef REALLY_SLOW_IO          /* most systems can safely undef this */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/string.h>
@@ -74,44 +73,53 @@ static void generic_id(ide_drive_t *drive)
        drive->id->cur_heads = drive->head;
        drive->id->cur_sectors = drive->sect;
 }
-               
-/**
- *     drive_is_flashcard      -       check for compact flash
- *     @drive: drive to check
- *
- *     CompactFlash cards and their brethern pretend to be removable
- *     hard disks, except:
- *             (1) they never have a slave unit, and
- *             (2) they don't have doorlock mechanisms.
- *     This test catches them, and is invoked elsewhere when setting
- *     appropriate config bits.
- *
- *     FIXME: This treatment is probably applicable for *all* PCMCIA (PC CARD)
- *     devices, so in linux 2.3.x we should change this to just treat all
- *     PCMCIA  drives this way, and get rid of the model-name tests below
- *     (too big of an interface change for 2.4.x).
- *     At that time, we might also consider parameterizing the timeouts and
- *     retries, since these are MUCH faster than mechanical drives. -M.Lord
- */
-static inline int drive_is_flashcard (ide_drive_t *drive)
+
+static void ide_disk_init_chs(ide_drive_t *drive)
 {
        struct hd_driveid *id = drive->id;
 
-       if (drive->removable) {
-               if (id->config == 0x848a) return 1;     /* CompactFlash */
-               if (!strncmp(id->model, "KODAK ATA_FLASH", 15)  /* Kodak */
-                || !strncmp(id->model, "Hitachi CV", 10)       /* Hitachi */
-                || !strncmp(id->model, "SunDisk SDCFB", 13)    /* old SanDisk */
-                || !strncmp(id->model, "SanDisk SDCFB", 13)    /* SanDisk */
-                || !strncmp(id->model, "HAGIWARA HPC", 12)     /* Hagiwara */
-                || !strncmp(id->model, "LEXAR ATA_FLASH", 15)  /* Lexar */
-                || !strncmp(id->model, "ATA_FLASH", 9))        /* Simple Tech */
-               {
-                       return 1;       /* yes, it is a flash memory card */
-               }
+       /* Extract geometry if we did not already have one for the drive */
+       if (!drive->cyl || !drive->head || !drive->sect) {
+               drive->cyl  = drive->bios_cyl  = id->cyls;
+               drive->head = drive->bios_head = id->heads;
+               drive->sect = drive->bios_sect = id->sectors;
+       }
+
+       /* Handle logical geometry translation by the drive */
+       if ((id->field_valid & 1) && id->cur_cyls &&
+           id->cur_heads && (id->cur_heads <= 16) && id->cur_sectors) {
+               drive->cyl  = id->cur_cyls;
+               drive->head = id->cur_heads;
+               drive->sect = id->cur_sectors;
+       }
+
+       /* Use physical geometry if what we have still makes no sense */
+       if (drive->head > 16 && id->heads && id->heads <= 16) {
+               drive->cyl  = id->cyls;
+               drive->head = id->heads;
+               drive->sect = id->sectors;
+       }
+}
+
+static void ide_disk_init_mult_count(ide_drive_t *drive)
+{
+       struct hd_driveid *id = drive->id;
+
+       drive->mult_count = 0;
+       if (id->max_multsect) {
+#ifdef CONFIG_IDEDISK_MULTI_MODE
+               id->multsect = ((id->max_multsect/2) > 1) ? id->max_multsect : 0;
+               id->multsect_valid = id->multsect ? 1 : 0;
+               drive->mult_req = id->multsect_valid ? id->max_multsect : INITIAL_MULT_COUNT;
+               drive->special.b.set_multmode = drive->mult_req ? 1 : 0;
+#else  /* original, pre IDE-NFG, per request of AC */
+               drive->mult_req = INITIAL_MULT_COUNT;
+               if (drive->mult_req > id->max_multsect)
+                       drive->mult_req = id->max_multsect;
+               if (drive->mult_req || ((id->multsect_valid & 1) && id->multsect))
+                       drive->special.b.set_multmode = 1;
+#endif
        }
-       return 0;       /* no, it is not a flash memory card */
 }
 
 /**
@@ -180,12 +188,6 @@ static inline void do_identify (ide_drive_t *drive, u8 cmd)
        if (cmd == WIN_PIDENTIFY) {
                u8 type = (id->config >> 8) & 0x1f;
                printk("ATAPI ");
-#ifdef CONFIG_BLK_DEV_PDC4030
-               if (hwif->channel == 1 && hwif->chipset == ide_pdc4030) {
-                       printk(" -- not supported on 2nd Promise port\n");
-                       goto err_misc;
-               }
-#endif /* CONFIG_BLK_DEV_PDC4030 */
                switch (type) {
                        case ide_floppy:
                                if (!strstr(id->model, "CD-ROM")) {
@@ -227,19 +229,25 @@ static inline void do_identify (ide_drive_t *drive, u8 cmd)
                }
                printk (" drive\n");
                drive->media = type;
+               /* an ATAPI device ignores DRDY */
+               drive->ready_stat = 0;
                return;
        }
 
        /*
         * Not an ATAPI device: looks like a "regular" hard disk
         */
-       if (id->config & (1<<7))
+
+       /*
+        * 0x848a = CompactFlash device
+        * These are *not* removable in Linux definition of the term
+        */
+
+       if ((id->config != 0x848a) && (id->config & (1<<7)))
                drive->removable = 1;
 
-       if (drive_is_flashcard(drive))
-               drive->is_flash = 1;
        drive->media = ide_disk;
-       printk("%s DISK drive\n", (drive->is_flash) ? "CFA" : "ATA" );
+       printk("%s DISK drive\n", (id->config == 0x848a) ? "CFA" : "ATA" );
        QUIRK_LIST(drive);
        return;
 
@@ -297,13 +305,9 @@ static int actual_try_to_identify (ide_drive_t *drive, u8 cmd)
                /* disable dma & overlap */
                hwif->OUTB(0, IDE_FEATURE_REG);
 
-       if (hwif->identify != NULL) {
-               if (hwif->identify(drive))
-                       return 1;
-       } else {
-               /* ask drive for ID */
-               hwif->OUTB(cmd, IDE_COMMAND_REG);
-       }
+       /* ask drive for ID */
+       hwif->OUTB(cmd, IDE_COMMAND_REG);
+
        timeout = ((cmd == WIN_IDENTIFY) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2;
        timeout += jiffies;
        do {
@@ -389,15 +393,6 @@ static int try_to_identify (ide_drive_t *drive, u8 cmd)
                                 */
                                printk("%s: IRQ probe failed (0x%lx)\n",
                                        drive->name, cookie);
-#ifdef CONFIG_BLK_DEV_CMD640
-#ifdef CMD640_DUMP_REGS
-                               if (hwif->chipset == ide_cmd640) {
-                                       printk("%s: Hmmm.. probably a driver "
-                                               "problem.\n", drive->name);
-                                       CMD640_DUMP_REGS;
-                               }
-#endif /* CMD640_DUMP_REGS */
-#endif /* CONFIG_BLK_DEV_CMD640 */
                        }
                }
        }
@@ -564,14 +559,13 @@ static inline u8 probe_for_drive (ide_drive_t *drive)
         *      Also note that 0 everywhere means "can't do X"
         */
  
-       drive->id = kmalloc(SECTOR_WORDS *4, GFP_KERNEL);
+       drive->id = kzalloc(SECTOR_WORDS *4, GFP_KERNEL);
        drive->id_read = 0;
        if(drive->id == NULL)
        {
                printk(KERN_ERR "ide: out of memory for id data.\n");
                return 0;
        }
-       memset(drive->id, 0, SECTOR_WORDS * 4);
        strcpy(drive->id->model, "UNKNOWN");
        
        /* skip probing? */
@@ -607,8 +601,16 @@ static inline u8 probe_for_drive (ide_drive_t *drive)
        if(!drive->present)
                return 0;
        /* The drive wasn't being helpful. Add generic info only */
-       if(!drive->id_read)
+       if (drive->id_read == 0) {
                generic_id(drive);
+               return 1;
+       }
+
+       if (drive->media == ide_disk) {
+               ide_disk_init_chs(drive);
+               ide_disk_init_mult_count(drive);
+       }
+
        return drive->present;
 }
 
@@ -616,11 +618,13 @@ static void hwif_release_dev (struct device *dev)
 {
        ide_hwif_t *hwif = container_of(dev, ide_hwif_t, gendev);
 
-       up(&hwif->gendev_rel_sem);
+       complete(&hwif->gendev_rel_comp);
 }
 
 static void hwif_register (ide_hwif_t *hwif)
 {
+       int ret;
+
        /* register with global device tree */
        strlcpy(hwif->gendev.bus_id,hwif->name,BUS_ID_SIZE);
        hwif->gendev.driver_data = hwif;
@@ -632,15 +636,17 @@ static void hwif_register (ide_hwif_t *hwif)
                        hwif->gendev.parent = NULL;
        }
        hwif->gendev.release = hwif_release_dev;
-       device_register(&hwif->gendev);
+       ret = device_register(&hwif->gendev);
+       if (ret < 0)
+               printk(KERN_WARNING "IDE: %s: device_register error: %d\n",
+                       __FUNCTION__, ret);
 }
 
-#ifdef CONFIG_PPC
 static int wait_hwif_ready(ide_hwif_t *hwif)
 {
        int rc;
 
-       printk(KERN_INFO "Probing IDE interface %s...\n", hwif->name);
+       printk(KERN_DEBUG "Probing IDE interface %s...\n", hwif->name);
 
        /* Let HW settle down a bit from whatever init state we
         * come from */
@@ -658,20 +664,56 @@ static int wait_hwif_ready(ide_hwif_t *hwif)
        SELECT_DRIVE(&hwif->drives[0]);
        hwif->OUTB(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
        mdelay(2);
-       rc = ide_wait_not_busy(hwif, 10000);
+       rc = ide_wait_not_busy(hwif, 35000);
        if (rc)
                return rc;
        SELECT_DRIVE(&hwif->drives[1]);
        hwif->OUTB(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
        mdelay(2);
-       rc = ide_wait_not_busy(hwif, 10000);
+       rc = ide_wait_not_busy(hwif, 35000);
 
        /* Exit function with master reselected (let's be sane) */
        SELECT_DRIVE(&hwif->drives[0]);
        
        return rc;
 }
-#endif
+
+/**
+ *     ide_undecoded_slave     -       look for bad CF adapters
+ *     @hwif: interface
+ *
+ *     Analyse the drives on the interface and attempt to decide if we
+ *     have the same drive viewed twice. This occurs with crap CF adapters
+ *     and PCMCIA sometimes.
+ */
+
+void ide_undecoded_slave(ide_hwif_t *hwif)
+{
+       ide_drive_t *drive0 = &hwif->drives[0];
+       ide_drive_t *drive1 = &hwif->drives[1];
+
+       if (drive0->present == 0 || drive1->present == 0)
+               return;
+
+       /* If the models don't match they are not the same product */
+       if (strcmp(drive0->id->model, drive1->id->model))
+               return;
+
+       /* Serial numbers do not match */
+       if (strncmp(drive0->id->serial_no, drive1->id->serial_no, 20))
+               return;
+
+       /* No serial number, thankfully very rare for CF */
+       if (drive0->id->serial_no[0] == 0)
+               return;
+
+       /* Appears to be an IDE flash adapter with decode bugs */
+       printk(KERN_WARNING "ide-probe: ignoring undecoded slave\n");
+
+       drive1->present = 0;
+}
+
+EXPORT_SYMBOL_GPL(ide_undecoded_slave);
 
 /*
  * This routine only knows how to look for drive units 0 and 1
@@ -687,9 +729,6 @@ static void probe_hwif(ide_hwif_t *hwif)
                return;
 
        if ((hwif->chipset != ide_4drives || !hwif->mate || !hwif->mate->present) &&
-#ifdef CONFIG_BLK_DEV_PDC4030
-           (hwif->chipset != ide_pdc4030 || hwif->channel == 0) &&
-#endif /* CONFIG_BLK_DEV_PDC4030 */
            (ide_hwif_request_regions(hwif))) {
                u16 msgout = 0;
                for (unit = 0; unit < MAX_DRIVES; ++unit) {
@@ -717,7 +756,6 @@ static void probe_hwif(ide_hwif_t *hwif)
 
        local_irq_set(flags);
 
-#ifdef CONFIG_PPC
        /* This is needed on some PPCs and a bunch of BIOS-less embedded
         * platforms. Typical cases are:
         * 
@@ -737,9 +775,8 @@ static void probe_hwif(ide_hwif_t *hwif)
         *  
         *  BenH.
         */
-       if (wait_hwif_ready(hwif))
-               printk(KERN_WARNING "%s: Wait for ready failed before probe !\n", hwif->name);
-#endif /* CONFIG_PPC */
+       if (wait_hwif_ready(hwif) == -EBUSY)
+               printk(KERN_DEBUG "%s: Wait for ready failed before probe !\n", hwif->name);
 
        /*
         * Second drive should only exist if first drive was found,
@@ -793,6 +830,13 @@ static void probe_hwif(ide_hwif_t *hwif)
                                drive->autotune == IDE_TUNE_AUTO)
                                /* auto-tune PIO mode */
                                hwif->tuneproc(drive, 255);
+
+                       if (drive->autotune != IDE_TUNE_DEFAULT &&
+                           drive->autotune != IDE_TUNE_AUTO)
+                               continue;
+
+                       drive->nice1 = 1;
+
                        /*
                         * MAJOR HACK BARF :-/
                         *
@@ -802,9 +846,7 @@ static void probe_hwif(ide_hwif_t *hwif)
                         * Move here to prevent module loading clashing.
                         */
        //              drive->autodma = hwif->autodma;
-                       if ((hwif->ide_dma_check) &&
-                               ((drive->autotune == IDE_TUNE_DEFAULT) ||
-                               (drive->autotune == IDE_TUNE_AUTO))) {
+                       if (hwif->ide_dma_check) {
                                /*
                                 * Force DMAing for the beginning of the check.
                                 * Some chipsets appear to do interesting
@@ -819,29 +861,58 @@ static void probe_hwif(ide_hwif_t *hwif)
                        }
                }
        }
+
+       for (unit = 0; unit < MAX_DRIVES; ++unit) {
+               ide_drive_t *drive = &hwif->drives[unit];
+
+               if (hwif->no_io_32bit)
+                       drive->no_io_32bit = 1;
+               else
+                       drive->no_io_32bit = drive->id->dword_io ? 1 : 0;
+       }
 }
 
 static int hwif_init(ide_hwif_t *hwif);
-int probe_hwif_init (ide_hwif_t *hwif)
+
+int probe_hwif_init_with_fixup(ide_hwif_t *hwif, void (*fixup)(ide_hwif_t *hwif))
 {
        probe_hwif(hwif);
-       hwif_init(hwif);
+
+       if (fixup)
+               fixup(hwif);
+
+       if (!hwif_init(hwif)) {
+               printk(KERN_INFO "%s: failed to initialize IDE interface\n",
+                                hwif->name);
+               return -1;
+       }
 
        if (hwif->present) {
                u16 unit = 0;
+               int ret;
+
                for (unit = 0; unit < MAX_DRIVES; ++unit) {
                        ide_drive_t *drive = &hwif->drives[unit];
                        /* For now don't attach absent drives, we may
                           want them on default or a new "empty" class
                           for hotplug reprobing ? */
                        if (drive->present) {
-                               ata_attach(drive);
+                               ret = device_register(&drive->gendev);
+                               if (ret < 0)
+                                       printk(KERN_WARNING "IDE: %s: "
+                                               "device_register error: %d\n",
+                                               __FUNCTION__, ret);
                        }
                }
        }
        return 0;
 }
 
+int probe_hwif_init(ide_hwif_t *hwif)
+{
+       return probe_hwif_init_with_fixup(hwif, NULL);
+}
+
 EXPORT_SYMBOL(probe_hwif_init);
 
 #if MAX_HWIFS > 1
@@ -888,16 +959,20 @@ static int ide_init_queue(ide_drive_t *drive)
         *      limits and LBA48 we could raise it but as yet
         *      do not.
         */
-        
-       q = blk_init_queue(do_ide_request, &ide_lock);
+
+       q = blk_init_queue_node(do_ide_request, &ide_lock, hwif_to_node(hwif));
        if (!q)
                return 1;
 
-       q->queuedata = HWGROUP(drive);
+       q->queuedata = drive;
        blk_queue_segment_boundary(q, 0xffff);
 
-       if (!hwif->rqsize)
-               hwif->rqsize = hwif->no_lba48 ? 256 : 65536;
+       if (!hwif->rqsize) {
+               if (hwif->no_lba48 || hwif->no_lba48_dma)
+                       hwif->rqsize = 256;
+               else
+                       hwif->rqsize = 65536;
+       }
        if (hwif->rqsize < max_sectors)
                max_sectors = hwif->rqsize;
        blk_queue_max_sectors(q, max_sectors);
@@ -906,11 +981,11 @@ static int ide_init_queue(ide_drive_t *drive)
        /* When we have an IOMMU, we may have a problem where pci_map_sg()
         * creates segments that don't completely match our boundary
         * requirements and thus need to be broken up again. Because it
-        * doesn't align properly neither, we may actually have to break up
+        * doesn't align properly either, we may actually have to break up
         * to more segments than what was we got in the first place, a max
         * worst case is twice as many.
         * This will be fixed once we teach pci_map_sg() about our boundary
-        * requirements, hopefully soon
+        * requirements, hopefully soon. *FIXME*
         */
        if (!PCI_DMA_BUS_IS_PHYS)
                max_sg_entries >>= 1;
@@ -919,18 +994,12 @@ static int ide_init_queue(ide_drive_t *drive)
        blk_queue_max_hw_segments(q, max_sg_entries);
        blk_queue_max_phys_segments(q, max_sg_entries);
 
-       /* assign drive and gendisk queue */
+       /* assign drive queue */
        drive->queue = q;
-       if (drive->disk)
-               drive->disk->queue = drive->queue;
 
        /* needs drive->queue to be set */
        ide_toggle_bounce(drive, 1);
 
-       /* enable led activity for disk drives only */
-       if (drive->media == ide_disk && hwif->led_act)
-               blk_queue_activity_fn(q, hwif->led_act, drive);
-
        return 0;
 }
 
@@ -942,7 +1011,7 @@ static int ide_init_queue(ide_drive_t *drive)
  * and irq serialization situations.  This is somewhat complex because
  * it handles static as well as dynamic (PCMCIA) IDE interfaces.
  *
- * The SA_INTERRUPT in sa_flags means ide_intr() is always entered with
+ * The IRQF_DISABLED in sa_flags means ide_intr() is always entered with
  * interrupts completely disabled.  This can be bad for interrupt latency,
  * but anything else has led to problems on some machines.  We re-enable
  * interrupts as much as we can safely do in most places.
@@ -956,6 +1025,8 @@ static int init_irq (ide_hwif_t *hwif)
 
        BUG_ON(in_interrupt());
        BUG_ON(irqs_disabled());        
+       BUG_ON(hwif == NULL);
+
        down(&ide_cfg_sem);
        hwif->hwgroup = NULL;
 #if MAX_HWIFS > 1
@@ -1004,7 +1075,8 @@ static int init_irq (ide_hwif_t *hwif)
                hwgroup->hwif->next = hwif;
                spin_unlock_irq(&ide_lock);
        } else {
-               hwgroup = kmalloc(sizeof(ide_hwgroup_t),GFP_KERNEL);
+               hwgroup = kmalloc_node(sizeof(ide_hwgroup_t), GFP_KERNEL,
+                                       hwif_to_node(hwif->drives[0].hwif));
                if (!hwgroup)
                        goto out_up;
 
@@ -1025,15 +1097,15 @@ static int init_irq (ide_hwif_t *hwif)
         * Allocate the irq, if not already obtained for another hwif
         */
        if (!match || match->irq != hwif->irq) {
-               int sa = SA_INTERRUPT;
+               int sa = IRQF_DISABLED;
 #if defined(__mc68000__) || defined(CONFIG_APUS)
-               sa = SA_SHIRQ;
+               sa = IRQF_SHARED;
 #endif /* __mc68000__ || CONFIG_APUS */
 
                if (IDE_CHIPSET_IS_PCI(hwif->chipset)) {
-                       sa = SA_SHIRQ;
+                       sa = IRQF_SHARED;
 #ifndef CONFIG_IDEPCI_SHARE_IRQ
-                       sa |= SA_INTERRUPT;
+                       sa |= IRQF_DISABLED;
 #endif /* CONFIG_IDEPCI_SHARE_IRQ */
                }
 
@@ -1071,16 +1143,11 @@ static int init_irq (ide_hwif_t *hwif)
                spin_unlock_irq(&ide_lock);
        }
 
-#if !defined(__mc68000__) && !defined(CONFIG_APUS) && !defined(__sparc__)
+#if !defined(__mc68000__) && !defined(CONFIG_APUS)
        printk("%s at 0x%03lx-0x%03lx,0x%03lx on irq %d", hwif->name,
                hwif->io_ports[IDE_DATA_OFFSET],
                hwif->io_ports[IDE_DATA_OFFSET]+7,
                hwif->io_ports[IDE_CONTROL_OFFSET], hwif->irq);
-#elif defined(__sparc__)
-       printk("%s at 0x%03lx-0x%03lx,0x%03lx on irq %s", hwif->name,
-               hwif->io_ports[IDE_DATA_OFFSET],
-               hwif->io_ports[IDE_DATA_OFFSET]+7,
-               hwif->io_ports[IDE_CONTROL_OFFSET], __irq_itoa(hwif->irq));
 #else
        printk("%s at 0x%08lx on irq %d", hwif->name,
                hwif->io_ports[IDE_DATA_OFFSET], hwif->irq);
@@ -1122,66 +1189,113 @@ static int ata_lock(dev_t dev, void *data)
        return 0;
 }
 
-extern ide_driver_t idedefault_driver;
-
-struct kobject *ata_probe(dev_t dev, int *part, void *data)
+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];
        if (!drive->present)
                return NULL;
-       if (drive->driver == &idedefault_driver) {
-               if (drive->media == ide_disk)
-                       (void) request_module("ide-disk");
-               if (drive->scsi)
-                       (void) request_module("ide-scsi");
-               if (drive->media == ide_cdrom || drive->media == ide_optical)
-                       (void) request_module("ide-cd");
-               if (drive->media == ide_tape)
-                       (void) request_module("ide-tape");
-               if (drive->media == ide_floppy)
-                       (void) request_module("ide-floppy");
-       }
-       if (drive->driver == &idedefault_driver)
-               return NULL;
+
+       if (drive->media == ide_disk)
+               request_module("ide-disk");
+       if (drive->scsi)
+               request_module("ide-scsi");
+       if (drive->media == ide_cdrom || drive->media == ide_optical)
+               request_module("ide-cd");
+       if (drive->media == ide_tape)
+               request_module("ide-tape");
+       if (drive->media == ide_floppy)
+               request_module("ide-floppy");
+
+       return NULL;
+}
+
+static struct kobject *exact_match(dev_t dev, int *part, void *data)
+{
+       struct gendisk *p = data;
        *part &= (1 << PARTN_BITS) - 1;
-       return get_disk(drive->disk);
+       return &p->kobj;
 }
 
-static int alloc_disks(ide_hwif_t *hwif)
+static int exact_lock(dev_t dev, void *data)
 {
-       unsigned int unit;
-       struct gendisk *disks[MAX_DRIVES];
+       struct gendisk *p = data;
 
-       for (unit = 0; unit < MAX_DRIVES; unit++) {
-               disks[unit] = alloc_disk(1 << PARTN_BITS);
-               if (!disks[unit])
-                       goto Enomem;
-       }
-       for (unit = 0; unit < MAX_DRIVES; ++unit) {
-               ide_drive_t *drive = &hwif->drives[unit];
-               struct gendisk *disk = disks[unit];
-               disk->major  = hwif->major;
-               disk->first_minor = unit << PARTN_BITS;
-               sprintf(disk->disk_name,"hd%c",'a'+hwif->index*MAX_DRIVES+unit);
-               disk->fops = ide_fops;
-               disk->private_data = drive;
-               drive->disk = disk;
-       }
+       if (!get_disk(p))
+               return -1;
        return 0;
-Enomem:
-       printk(KERN_WARNING "(ide::init_gendisk) Out of memory\n");
-       while (unit--)
-               put_disk(disks[unit]);
-       return -ENOMEM;
+}
+
+void ide_register_region(struct gendisk *disk)
+{
+       blk_register_region(MKDEV(disk->major, disk->first_minor),
+                           disk->minors, NULL, exact_match, exact_lock, disk);
+}
+
+EXPORT_SYMBOL_GPL(ide_register_region);
+
+void ide_unregister_region(struct gendisk *disk)
+{
+       blk_unregister_region(MKDEV(disk->major, disk->first_minor),
+                             disk->minors);
+}
+
+EXPORT_SYMBOL_GPL(ide_unregister_region);
+
+void ide_init_disk(struct gendisk *disk, ide_drive_t *drive)
+{
+       ide_hwif_t *hwif = drive->hwif;
+       unsigned int unit = (drive->select.all >> 4) & 1;
+
+       disk->major = hwif->major;
+       disk->first_minor = unit << PARTN_BITS;
+       sprintf(disk->disk_name, "hd%c", 'a' + hwif->index * MAX_DRIVES + unit);
+       disk->queue = drive->queue;
+}
+
+EXPORT_SYMBOL_GPL(ide_init_disk);
+
+static void ide_remove_drive_from_hwgroup(ide_drive_t *drive)
+{
+       ide_hwgroup_t *hwgroup = drive->hwif->hwgroup;
+
+       if (drive == drive->next) {
+               /* special case: last drive from hwgroup. */
+               BUG_ON(hwgroup->drive != drive);
+               hwgroup->drive = NULL;
+       } else {
+               ide_drive_t *walk;
+
+               walk = hwgroup->drive;
+               while (walk->next != drive)
+                       walk = walk->next;
+               walk->next = drive->next;
+               if (hwgroup->drive == drive) {
+                       hwgroup->drive = drive->next;
+                       hwgroup->hwif = hwgroup->drive->hwif;
+               }
+       }
+       BUG_ON(hwgroup->drive == drive);
 }
 
 static void drive_release_dev (struct device *dev)
 {
        ide_drive_t *drive = container_of(dev, ide_drive_t, gendev);
 
-       up(&drive->gendev_rel_sem);
+       spin_lock_irq(&ide_lock);
+       ide_remove_drive_from_hwgroup(drive);
+       kfree(drive->id);
+       drive->id = NULL;
+       drive->present = 0;
+       /* Messed up locking ... */
+       spin_unlock_irq(&ide_lock);
+       blk_cleanup_queue(drive->queue);
+       spin_lock_irq(&ide_lock);
+       drive->queue = NULL;
+       spin_unlock_irq(&ide_lock);
+
+       complete(&drive->gendev_rel_comp);
 }
 
 /*
@@ -1203,13 +1317,6 @@ static void init_gendisk (ide_hwif_t *hwif)
                drive->gendev.bus = &ide_bus_type;
                drive->gendev.driver_data = drive;
                drive->gendev.release = drive_release_dev;
-               if (drive->present) {
-                       device_register(&drive->gendev);
-                       sprintf(drive->devfs_name, "ide/host%d/bus%d/target%d/lun%d",
-                               (hwif->channel && hwif->mate) ?
-                               hwif->mate->index : hwif->index,
-                               hwif->channel, unit, drive->lun);
-               }
        }
        blk_register_region(MKDEV(hwif->major, 0), MAX_DRIVES << PARTN_BITS,
                        THIS_MODULE, ata_probe, ata_lock, hwif);
@@ -1217,10 +1324,11 @@ static void init_gendisk (ide_hwif_t *hwif)
 
 static int hwif_init(ide_hwif_t *hwif)
 {
-       int old_irq, unit;
+       int old_irq;
 
+       /* Return success if no device is connected */
        if (!hwif->present)
-               return 0;
+               return 1;
 
        if (!hwif->irq) {
                if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET])))
@@ -1243,8 +1351,15 @@ static int hwif_init(ide_hwif_t *hwif)
        if (register_blkdev(hwif->major, hwif->name))
                return 0;
 
-       if (alloc_disks(hwif) < 0)
+       if (!hwif->sg_max_nents)
+               hwif->sg_max_nents = PRD_ENTRIES;
+
+       hwif->sg_table = kmalloc(sizeof(struct scatterlist)*hwif->sg_max_nents,
+                                GFP_KERNEL);
+       if (!hwif->sg_table) {
+               printk(KERN_ERR "%s: unable to allocate SG table.\n", hwif->name);
                goto out;
+       }
        
        if (init_irq(hwif) == 0)
                goto done;
@@ -1257,12 +1372,12 @@ static int hwif_init(ide_hwif_t *hwif)
        if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET]))) {
                printk("%s: Disabled unable to get IRQ %d.\n",
                        hwif->name, old_irq);
-               goto out_disks;
+               goto out;
        }
        if (init_irq(hwif)) {
                printk("%s: probed IRQ %d and default IRQ %d failed.\n",
                        hwif->name, old_irq, hwif->irq);
-               goto out_disks;
+               goto out;
        }
        printk("%s: probed IRQ %d failed, using default.\n",
                hwif->name, hwif->irq);
@@ -1272,12 +1387,6 @@ done:
        hwif->present = 1;      /* success */
        return 1;
 
-out_disks:
-       for (unit = 0; unit < MAX_DRIVES; unit++) {
-               struct gendisk *disk = hwif->drives[unit].disk;
-               hwif->drives[unit].disk = NULL;
-               put_disk(disk);
-       }
 out:
        unregister_blkdev(hwif->major, hwif->name);
        return 0;
@@ -1292,9 +1401,6 @@ int ideprobe_init (void)
        for (index = 0; index < MAX_HWIFS; ++index)
                probe[index] = !ide_hwifs[index].present;
 
-       /*
-        * Probe for drives in the usual way.. CMOS/BIOS, then poke at ports
-        */
        for (index = 0; index < MAX_HWIFS; ++index)
                if (probe[index])
                        probe_hwif(&ide_hwifs[index]);
@@ -1310,8 +1416,14 @@ int ideprobe_init (void)
                        if (hwif->chipset == ide_unknown || hwif->chipset == ide_forced)
                                hwif->chipset = ide_generic;
                        for (unit = 0; unit < MAX_DRIVES; ++unit)
-                               if (hwif->drives[unit].present)
-                                       ata_attach(&hwif->drives[unit]);
+                               if (hwif->drives[unit].present) {
+                                       int ret = device_register(
+                                               &hwif->drives[unit].gendev);
+                                       if (ret < 0)
+                                               printk(KERN_WARNING "IDE: %s: "
+                                                       "device_register error: %d\n",
+                                                       __FUNCTION__, ret);
+                               }
                }
        }
        return 0;