fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / ide / ide-probe.c
index 417783f..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 */
 }
 
 /**
@@ -221,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;
 
@@ -545,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? */
@@ -588,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;
 }
 
@@ -597,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;
@@ -613,7 +636,10 @@ 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);
 }
 
 static int wait_hwif_ready(ide_hwif_t *hwif)
@@ -638,13 +664,13 @@ 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]);
@@ -804,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 :-/
                         *
@@ -813,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
@@ -830,6 +861,15 @@ 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);
@@ -849,13 +889,19 @@ int probe_hwif_init_with_fixup(ide_hwif_t *hwif, void (*fixup)(ide_hwif_t *hwif)
 
        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);
                        }
                }
        }
@@ -913,8 +959,8 @@ 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;
 
@@ -948,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;
 }
 
@@ -971,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.
@@ -985,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
@@ -1033,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;
 
@@ -1054,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 */
                }
 
@@ -1100,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);
@@ -1151,8 +1189,6 @@ static int ata_lock(dev_t dev, void *data)
        return 0;
 }
 
-extern ide_driver_t idedefault_driver;
-
 static struct kobject *ata_probe(dev_t dev, int *part, void *data)
 {
        ide_hwif_t *hwif = data;
@@ -1160,57 +1196,106 @@ static struct kobject *ata_probe(dev_t dev, int *part, void *data)
        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);
 }
 
 /*
@@ -1232,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);
@@ -1246,7 +1324,7 @@ 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)
@@ -1282,9 +1360,6 @@ static int hwif_init(ide_hwif_t *hwif)
                printk(KERN_ERR "%s: unable to allocate SG table.\n", hwif->name);
                goto out;
        }
-
-       if (alloc_disks(hwif) < 0)
-               goto out;
        
        if (init_irq(hwif) == 0)
                goto done;
@@ -1297,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);
@@ -1312,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;
@@ -1347,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;