#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/ide.h>
+#include <linux/devfs_fs_kernel.h>
#include <linux/spinlock.h>
#include <linux/kmod.h>
#include <linux/pci.h>
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 */
}
/**
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")) {
}
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;
/* 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 {
* 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? */
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;
}
{
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)
}
hwif->gendev.release = hwif_release_dev;
device_register(&hwif->gendev);
- hwif->configured = 1;
}
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]);
* and PCMCIA sometimes.
*/
-void ide_undecoded_slave(ide_hwif_t *hwif)
+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 */
+ 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))
+ 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;
- /* Has a serial number but is warped */
- if (!strstr(drive0->id->model, "Integrated Technology Express"))
- 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(ide_undecoded_slave);
+EXPORT_SYMBOL_GPL(ide_undecoded_slave);
/*
* This routine only knows how to look for drive units 0 and 1
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) {
*
* BenH.
*/
- if (wait_hwif_ready(hwif))
+ if (wait_hwif_ready(hwif) == -EBUSY)
printk(KERN_DEBUG "%s: Wait for ready failed before probe !\n", hwif->name);
/*
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 :-/
*
* 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
}
}
}
+
+ 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_with_fixup(ide_hwif_t *hwif, void (*fixup)(ide_hwif_t *hwif))
{
probe_hwif(hwif);
- if(fixup != NULL)
+
+ if (fixup)
fixup(hwif);
- hwif_init(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;
-
-
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);
+ device_register(&drive->gendev);
}
}
}
return 0;
}
-EXPORT_SYMBOL(probe_hwif_init_with_fixup);
-
int probe_hwif_init(ide_hwif_t *hwif)
{
return probe_hwif_init_with_fixup(hwif, NULL);
* 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;
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);
BUG_ON(in_interrupt());
BUG_ON(irqs_disabled());
+ BUG_ON(hwif == NULL);
+
down(&ide_cfg_sem);
hwif->hwgroup = NULL;
#if MAX_HWIFS > 1
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;
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);
+ if (drive->devfs_name[0] != '\0') {
+ devfs_remove(drive->devfs_name);
+ drive->devfs_name[0] = '\0';
+ }
+ 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);
}
/*
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,
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])))
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;
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);
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;
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]);
hwif->chipset = ide_generic;
for (unit = 0; unit < MAX_DRIVES; ++unit)
if (hwif->drives[unit].present)
- ata_attach(&hwif->drives[unit]);
+ device_register(&hwif->drives[unit].gendev);
}
}
return 0;