#include <linux/cdrom.h>
#include <linux/seq_file.h>
#include <linux/device.h>
+#include <linux/bitops.h>
#include <asm/byteorder.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <asm/io.h>
-#include <asm/bitops.h>
/* default maximum number of failures */
static int initializing; /* set while initializing built-in drivers */
DECLARE_MUTEX(ide_cfg_sem);
-EXPORT_SYMBOL_GPL(ide_cfg_sem);
-spinlock_t ide_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
+ __cacheline_aligned_in_smp DEFINE_SPINLOCK(ide_lock);
#ifdef CONFIG_BLK_DEV_IDEPCI
static int ide_scan_direction; /* THIS was formerly 2.2.x pci=reverse */
EXPORT_SYMBOL(ide_hwifs);
-extern ide_driver_t idedefault_driver;
-static void setup_driver_defaults(ide_driver_t *driver);
-
/*
* Do not even *think* about calling this!
*/
static void init_hwif_data(ide_hwif_t *hwif, unsigned int index)
{
unsigned int unit;
- unsigned int key = hwif->key;
/* bulk initialize hwif & drive info with zeros */
memset(hwif, 0, sizeof(ide_hwif_t));
/* fill in any non-zero initial values */
- hwif->key = key + 1; /* Protected by ide_cfg_sem */
hwif->index = index;
hwif->major = ide_hwif_to_major[index];
hwif->mwdma_mask = 0x80; /* disable all mwdma */
hwif->swdma_mask = 0x80; /* disable all swdma */
- sema_init(&hwif->gendev_rel_sem, 0);
+ init_completion(&hwif->gendev_rel_comp);
default_hwif_iops(hwif);
default_hwif_transport(hwif);
drive->name[2] = 'a' + (index * MAX_DRIVES) + unit;
drive->max_failures = IDE_DEFAULT_MAX_FAILURES;
drive->using_dma = 0;
- drive->is_flash = 0;
- drive->driver = &idedefault_driver;
drive->vdma = 0;
INIT_LIST_HEAD(&drive->list);
- sema_init(&drive->gendev_rel_sem, 0);
+ init_completion(&drive->gendev_rel_comp);
}
}
return; /* already initialized */
magic_cookie = 0;
- setup_driver_defaults(&idedefault_driver);
-
/* Initialise all interface structures */
for (index = 0; index < MAX_HWIFS; ++index) {
hwif = &ide_hwifs[index];
#endif
}
-/*
- * ide_drive_from_key - turn key into drive
- * @kval: persistent key
- *
- * Convert a key into a drive. Currently the key is packed as
- * [keyval] << 16 | hwif << 8 | drive_num. Caller must hold
- * ide_settings_sem for the duration of the returned reference
- */
-
-ide_drive_t *ide_drive_from_key(void *kval)
-{
- unsigned long key = (unsigned long) kval;
- int idx = (key >> 8) & 0xFF;
- int drive = key & 3;
- ide_hwif_t *hwif = &ide_hwifs[idx];
- ide_drive_t *ret;
-
- key >>= 16;
-
- if(hwif->configured == 0 || hwif->present == 0 || hwif->drives[drive].dead || hwif->key != key)
- ret = NULL;
- else
- ret = &ide_hwifs[idx].drives[drive];
-
- return ret;
-}
-
-EXPORT_SYMBOL_GPL(ide_drive_from_key);
-
-/*
- * ide_drive_to_key - turn drive to persistent key
- * @drive: drive to use
- *
- * Convert drive into a key. Currently the key is packed as
- * [keyval] << 16 | hwif << 8 | drive_num. Caller must hold
- * ide_settings_sem for the duration of the returned reference
- */
-
-void *ide_drive_to_key(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = HWIF(drive);
- unsigned long val;
-
- val = (hwif->index << 8) | (hwif->key << 16) | drive->select.b.unit;
- return (void *)val;
-}
-
-/*
- * ide_hwif_from_key - turn key into hwif
- * @kval: persistent key
- *
- * Convert a key into a drive. Currently the key is packed as
- * [keyval] << 16 | hwif << 8 | drive_num. Caller must hold
- * ide_settings_sem for the duration of the returned reference
- */
-
-ide_hwif_t *ide_hwif_from_key(void *kval)
-{
- unsigned long key = (unsigned long) kval;
- int idx = (key >> 8) & 0xFF;
- ide_hwif_t *hwif = &ide_hwifs[idx];
-
- key >>= 16;
-
- if(hwif->configured == 0 || hwif->present == 0 || hwif->key != key)
- return NULL;
- return hwif;
-}
-
-/*
- * ide_hwif_to_key - turn drive to persistent key
- * @hwif: hwif to use
- *
- * Convert drive into a key. Currently the key is packed as
- * [keyval] << 16 | hwif << 8 | drive_num. Caller must hold
- * ide_settings_sem for the duration of the returned reference
- */
-
-void *ide_hwif_to_key(ide_hwif_t *hwif)
-{
- unsigned long val;
-
- val = (hwif->index << 8) | (hwif->key << 16);
- return (void *)val;
-}
-
/**
* ide_system_bus_speed - guess bus speed
*
* Returns a guessed speed in MHz.
*/
-int ide_system_bus_speed (void)
+static int ide_system_bus_speed(void)
{
+#ifdef CONFIG_PCI
+ static struct pci_device_id pci_default[] = {
+ { PCI_DEVICE(PCI_ANY_ID, PCI_ANY_ID) },
+ { }
+ };
+#else
+#define pci_default 0
+#endif /* CONFIG_PCI */
+
if (!system_bus_speed) {
if (idebus_parameter) {
/* user supplied value */
system_bus_speed = idebus_parameter;
- } else if (pci_find_device(PCI_ANY_ID, PCI_ANY_ID, NULL) != NULL) {
+ } else if (pci_dev_present(pci_default)) {
/* safe default value for PCI */
system_bus_speed = 33;
} else {
return system_bus_speed;
}
-/**
- * current_capacity - drive capacity
- * @drive: drive to query
- *
- * Return the current capacity (in sectors) of a drive according to
- * its current geometry/LBA settings. Empty removables are reported
- * as size zero.
- */
-
-sector_t current_capacity (ide_drive_t *drive)
-{
- if (!drive->present)
- return 0;
- return DRIVER(drive)->capacity(drive);
-}
-
-EXPORT_SYMBOL(current_capacity);
-
-/**
- * ide_dump_status - translate ATA error
- * @drive: drive the error occured on
- * @msg: information string
- * @stat: status byte
- *
- * Error reporting, in human readable form (luxurious, but a memory hog).
- * Combines the drive name, message and status byte to provide a
- * user understandable explanation of the device error.
- */
-
-u8 ide_dump_status (ide_drive_t *drive, const char *msg, u8 stat)
-{
- ide_hwif_t *hwif = HWIF(drive);
- unsigned long flags;
- u8 err = 0;
-
- local_irq_set(flags);
- printk(KERN_WARNING "%s: %s: status=0x%02x", drive->name, msg, stat);
- printk(" { ");
- if (stat & BUSY_STAT) {
- printk("Busy ");
- } else {
- if (stat & READY_STAT) printk("DriveReady ");
- if (stat & WRERR_STAT) printk("DeviceFault ");
- if (stat & SEEK_STAT) printk("SeekComplete ");
- if (stat & DRQ_STAT) printk("DataRequest ");
- if (stat & ECC_STAT) printk("CorrectedError ");
- if (stat & INDEX_STAT) printk("Index ");
- if (stat & ERR_STAT) printk("Error ");
- }
- printk("}");
- printk("\n");
- if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
- err = hwif->INB(IDE_ERROR_REG);
- printk("%s: %s: error=0x%02x", drive->name, msg, err);
- if (drive->media == ide_disk) {
- printk(" { ");
- if (err & ABRT_ERR) printk("DriveStatusError ");
- if (err & ICRC_ERR) printk("Bad%s ", (err & ABRT_ERR) ? "CRC" : "Sector");
- if (err & ECC_ERR) printk("UncorrectableError ");
- if (err & ID_ERR) printk("SectorIdNotFound ");
- if (err & TRK0_ERR) printk("TrackZeroNotFound ");
- if (err & MARK_ERR) printk("AddrMarkNotFound ");
- printk("}");
- if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR || (err & (ECC_ERR|ID_ERR|MARK_ERR))) {
- if ((drive->id->command_set_2 & 0x0400) &&
- (drive->id->cfs_enable_2 & 0x0400) &&
- (drive->addressing == 1)) {
- u64 sectors = 0;
- u32 high = 0;
- u32 low = ide_read_24(drive);
- hwif->OUTB(drive->ctl|0x80, IDE_CONTROL_REG);
- high = ide_read_24(drive);
-
- sectors = ((u64)high << 24) | low;
- printk(", LBAsect=%llu, high=%d, low=%d",
- (long long) sectors,
- high, low);
- } else {
- u8 cur = hwif->INB(IDE_SELECT_REG);
- if (cur & 0x40) { /* using LBA? */
- printk(", LBAsect=%ld", (unsigned long)
- ((cur&0xf)<<24)
- |(hwif->INB(IDE_HCYL_REG)<<16)
- |(hwif->INB(IDE_LCYL_REG)<<8)
- | hwif->INB(IDE_SECTOR_REG));
- } else {
- printk(", CHS=%d/%d/%d",
- (hwif->INB(IDE_HCYL_REG)<<8) +
- hwif->INB(IDE_LCYL_REG),
- cur & 0xf,
- hwif->INB(IDE_SECTOR_REG));
- }
- }
- if (HWGROUP(drive) && HWGROUP(drive)->rq)
- printk(", sector=%llu", (unsigned long long)HWGROUP(drive)->rq->sector);
- }
- }
- printk("\n");
- }
- {
- struct request *rq;
- int opcode = 0x100;
-
- spin_lock(&ide_lock);
- rq = NULL;
- if (HWGROUP(drive))
- rq = HWGROUP(drive)->rq;
- spin_unlock(&ide_lock);
- if (!rq)
- goto out;
- if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK)) {
- char *args = rq->buffer;
- if (args)
- opcode = args[0];
- } else if (rq->flags & REQ_DRIVE_TASKFILE) {
- ide_task_t *args = rq->special;
- if (args) {
- task_struct_t *tf = (task_struct_t *) args->tfRegister;
- opcode = tf->command;
- }
- }
-
- printk("ide: failed opcode was %x\n", opcode);
- }
-out:
- local_irq_restore(flags);
- return err;
-}
-
-EXPORT_SYMBOL(ide_dump_status);
-
-static int ide_open (struct inode * inode, struct file * filp)
-{
- return -ENXIO;
-}
-
-/*
- * drives_lock protects the list of drives, drivers lock the
- * list of drivers. Currently nobody takes both at once.
- * drivers_sem guards the drivers_list for readers that may
- * sleep. It must be taken before drivers_lock. Take drivers_sem
- * before ide_setting_sem and idecfg_sem before either of the
- * others.
- */
-
-static spinlock_t drives_lock = SPIN_LOCK_UNLOCKED;
-static DECLARE_MUTEX(drivers_sem);
-static spinlock_t drivers_lock = SPIN_LOCK_UNLOCKED;
-static LIST_HEAD(drivers);
-
-/* Iterator for the driver list. */
-
-static void *m_start(struct seq_file *m, loff_t *pos)
-{
- struct list_head *p;
- loff_t l = *pos;
- down(&drivers_sem);
- list_for_each(p, &drivers)
- if (!l--)
- return list_entry(p, ide_driver_t, drivers);
- return NULL;
-}
-
-static void *m_next(struct seq_file *m, void *v, loff_t *pos)
-{
- struct list_head *p = ((ide_driver_t *)v)->drivers.next;
- (*pos)++;
- return p==&drivers ? NULL : list_entry(p, ide_driver_t, drivers);
-}
-
-static void m_stop(struct seq_file *m, void *v)
-{
- up(&drivers_sem);
-}
-
-static int show_driver(struct seq_file *m, void *v)
-{
- ide_driver_t *driver = v;
- seq_printf(m, "%s version %s\n", driver->name, driver->version);
- return 0;
-}
-
-struct seq_operations ide_drivers_op = {
- .start = m_start,
- .next = m_next,
- .stop = m_stop,
- .show = show_driver
-};
-
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *proc_ide_root;
-
-ide_proc_entry_t generic_subdriver_entries[] = {
- { "capacity", S_IFREG|S_IRUGO, proc_ide_read_capacity, NULL },
- { NULL, 0, NULL, NULL }
-};
#endif
static struct resource* hwif_request_region(ide_hwif_t *hwif,
hwif->cds = tmp_hwif->cds;
#endif
- hwif->identify = tmp_hwif->identify;
hwif->tuneproc = tmp_hwif->tuneproc;
hwif->speedproc = tmp_hwif->speedproc;
hwif->selectproc = tmp_hwif->selectproc;
hwif->maskproc = tmp_hwif->maskproc;
hwif->quirkproc = tmp_hwif->quirkproc;
hwif->busproc = tmp_hwif->busproc;
- hwif->raw_taskfile = tmp_hwif->raw_taskfile;
hwif->ata_input_data = tmp_hwif->ata_input_data;
hwif->ata_output_data = tmp_hwif->ata_output_data;
hwif->atapi_input_bytes = tmp_hwif->atapi_input_bytes;
hwif->atapi_output_bytes = tmp_hwif->atapi_output_bytes;
- hwif->ide_dma_read = tmp_hwif->ide_dma_read;
- hwif->ide_dma_write = tmp_hwif->ide_dma_write;
- hwif->ide_dma_begin = tmp_hwif->ide_dma_begin;
+ hwif->dma_setup = tmp_hwif->dma_setup;
+ hwif->dma_exec_cmd = tmp_hwif->dma_exec_cmd;
+ hwif->dma_start = tmp_hwif->dma_start;
hwif->ide_dma_end = tmp_hwif->ide_dma_end;
hwif->ide_dma_check = tmp_hwif->ide_dma_check;
hwif->ide_dma_on = tmp_hwif->ide_dma_on;
hwif->ide_dma_test_irq = tmp_hwif->ide_dma_test_irq;
hwif->ide_dma_host_on = tmp_hwif->ide_dma_host_on;
hwif->ide_dma_host_off = tmp_hwif->ide_dma_host_off;
- hwif->ide_dma_verbose = tmp_hwif->ide_dma_verbose;
hwif->ide_dma_lostirq = tmp_hwif->ide_dma_lostirq;
hwif->ide_dma_timeout = tmp_hwif->ide_dma_timeout;
hwif->INSW = tmp_hwif->INSW;
hwif->INSL = tmp_hwif->INSL;
+ hwif->sg_max_nents = tmp_hwif->sg_max_nents;
+
hwif->mmio = tmp_hwif->mmio;
hwif->rqsize = tmp_hwif->rqsize;
hwif->no_lba48 = tmp_hwif->no_lba48;
}
/**
- * __ide_unregister_hwif - free an ide interface
- * @hwif: interface to unregister
+ * ide_unregister - free an ide interface
+ * @index: index of interface (will change soon to a pointer)
*
* Perform the final unregister of an IDE interface. At the moment
* we don't refcount interfaces so this will also get split up.
*
* Locking:
- * The caller must not hold the IDE locks except for ide_cfg_sem
- * which must be held.
- *
+ * The caller must not hold the IDE locks
* The drive present/vanishing is not yet properly locked
* Take care with the callbacks. These have been split to avoid
* deadlocking the IDE layer. The shutdown callback is called
* isnt yet done btw). After we commit to the final kill we
* call the cleanup callback with the ide locks held.
*
- * An interface can be in four states we care about
- * - It can be busy (drive or driver thinks its active). No unload
- * - It can be unconfigured - which means its already gone
- * - It can be configured and present - a full interface
- * - It can be configured and not present - pci configured but no drives
- * so logically absent.
- *
* Unregister restores the hwif structures to the default state.
+ * This is raving bonkers.
*/
-int __ide_unregister_hwif(ide_hwif_t *hwif)
+void ide_unregister(unsigned int index)
{
- ide_drive_t *drive = NULL; /* keep compiler happy */
- ide_hwif_t *g;
+ ide_drive_t *drive;
+ ide_hwif_t *hwif, *g;
static ide_hwif_t tmp_hwif; /* protected by ide_cfg_sem */
ide_hwgroup_t *hwgroup;
- int irq_count = 0, unit, i;
- int was_present;
- int ret = 0;
- int index = hwif->index;
+ int irq_count = 0, unit;
+
+ BUG_ON(index >= MAX_HWIFS);
BUG_ON(in_interrupt());
BUG_ON(irqs_disabled());
-
- /* Make sure nobody sneaks in via the proc interface */
- down(&ide_setting_sem);
-
- /* Now ensure nobody gets in for I/O while we clean up and
- do the busy check. If busy is set then the device is still
- open and we must stop */
+ down(&ide_cfg_sem);
spin_lock_irq(&ide_lock);
-
- if (!hwif->configured)
+ hwif = &ide_hwifs[index];
+ if (!hwif->present)
goto abort;
for (unit = 0; unit < MAX_DRIVES; ++unit) {
drive = &hwif->drives[unit];
- if (!drive->present)
+ if (!drive->present) {
+ if (drive->devfs_name[0] != '\0') {
+ devfs_remove(drive->devfs_name);
+ drive->devfs_name[0] = '\0';
+ }
continue;
- if (drive->usage || DRIVER(drive)->busy)
- goto abort;
- drive->dead = 1;
+ }
+ spin_unlock_irq(&ide_lock);
+ device_unregister(&drive->gendev);
+ wait_for_completion(&drive->gendev_rel_comp);
+ spin_lock_irq(&ide_lock);
}
- /*
- * Protect against new users. From this point the hwif
- * is not present so cannot be opened by a new I/O source.
- * This also invalidates key driven access from procfs
- */
-
- was_present = hwif->present;
hwif->present = 0;
spin_unlock_irq(&ide_lock);
- up(&ide_setting_sem);
-
- for (unit = 0; unit < MAX_DRIVES; ++unit) {
- drive = &hwif->drives[unit];
- if (!drive->present)
- continue;
- DRIVER(drive)->cleanup(drive);
- }
-#ifdef CONFIG_PROC_FS
- destroy_proc_ide_drives(hwif);
destroy_proc_ide_interface(hwif);
-#endif
- spin_lock_irq(&ide_lock);
hwgroup = hwif->hwgroup;
- if(hwgroup)
- {
- /*
- * free the irq if we were the only hwif using it
- */
- g = hwgroup->hwif;
- do {
- if (g->irq == hwif->irq)
- ++irq_count;
- g = g->next;
- } while (g != hwgroup->hwif);
- }
- spin_unlock_irq(&ide_lock);
-
- if (irq_count == 1 && hwgroup)
+ /*
+ * free the irq if we were the only hwif using it
+ */
+ g = hwgroup->hwif;
+ do {
+ if (g->irq == hwif->irq)
+ ++irq_count;
+ g = g->next;
+ } while (g != hwgroup->hwif);
+ if (irq_count == 1)
free_irq(hwif->irq, hwgroup);
+ spin_lock_irq(&ide_lock);
/*
* Note that we only release the standard ports,
* and do not even try to handle any extra ports
* allocated for weird IDE interface chipsets.
- *
- * FIXME: should defer this I think
*/
-
- if(was_present)
- ide_hwif_release_regions(hwif);
+ ide_hwif_release_regions(hwif);
/*
* Remove us from the hwgroup, and free
* the hwgroup if we were the only member
*/
- for (i = 0; i < MAX_DRIVES; ++i) {
- drive = &hwif->drives[i];
- if (drive->devfs_name[0] != '\0') {
- devfs_remove(drive->devfs_name);
- drive->devfs_name[0] = '\0';
- }
- if (!drive->present)
- continue;
-
- /*
- * The hwgroup chain is IRQ touched. We must protect
- * walking this from an IDE event for another device
- * in the chain
- */
-
- spin_lock_irq(&ide_lock);
- 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 = HWIF(hwgroup->drive);
- }
- }
- spin_unlock_irq(&ide_lock);
-
- /*
- * The rest of the cleanup is private
+ 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.
*/
-
- BUG_ON(hwgroup->drive == drive);
- if (drive->id != NULL) {
- kfree(drive->id);
- drive->id = NULL;
- }
- drive->present = 0;
- blk_cleanup_queue(drive->queue);
- device_unregister(&drive->gendev);
- down(&drive->gendev_rel_sem);
- drive->queue = NULL;
- }
- /*
- * Lock against hwgroup walkers including interrupts off other
- * IDE devices wile we unhook ourselves.
- */
-
- spin_lock_irq(&ide_lock);
-
- if (hwgroup)
- {
- 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.
+ 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.
*/
- 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);
+ BUG_ON(hwgroup->drive != NULL);
+ hwgroup->hwif = g;
}
+ BUG_ON(hwgroup->hwif == hwif);
}
- spin_unlock_irq(&ide_lock);
- /*
- * PCI interfaces with no devices don't exist in the device
- * tree so don't unregister them.
- */
-
- if(was_present)
- {
- device_unregister(&hwif->gendev);
- down(&hwif->gendev_rel_sem);
- }
+ /* More messed up locking ... */
+ spin_unlock_irq(&ide_lock);
+ 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<<PARTN_BITS);
- for (i = 0; i < MAX_DRIVES; i++) {
- struct gendisk *disk = hwif->drives[i].disk;
- hwif->drives[i].disk = NULL;
- put_disk(disk);
- }
+ kfree(hwif->sg_table);
unregister_blkdev(hwif->major, hwif->name);
spin_lock_irq(&ide_lock);
- /*
- * Let the driver free up private objects
- */
-
- if(hwif->remove)
- hwif->remove(hwif);
-
if (hwif->dma_base) {
(void) ide_release_dma(hwif);
hwif->dma_vendor3 = 0;
hwif->dma_prdtable = 0;
}
- hwif->chipset = ide_unknown;
/* copy original settings */
tmp_hwif = *hwif;
init_hwif_data(hwif, index);
init_hwif_default(hwif, index);
- hwif->configured = 0;
-
ide_hwif_restore(hwif, &tmp_hwif);
-
- spin_unlock_irq(&ide_lock);
- return 0;
abort:
- if(hwif->configured)
- {
- printk("Unregister %d fail %d %d\n", index, drive->usage, DRIVER(drive)->busy);
- ret = -EBUSY;
- }
- else
- {
- printk("No such hwif!\n");
- ret = -ENOENT;
- }
spin_unlock_irq(&ide_lock);
- up(&ide_setting_sem);
- return ret;
-}
-
-EXPORT_SYMBOL_GPL(__ide_unregister_hwif);
-
-/**
- * ide_unregister_hwif - free an ide interface
- * @hwif: interface to unregister
- *
- * Perform the final unregister of an IDE interface. At the moment
- * we don't refcount interfaces so this will also get split up.
- * Unregister restores the hwif structures to the default state.
- *
- * No locks should be held on entry. When an unregister must
- * be done atomically with a register see __ide_unregister_hwif
- * and hold the ide_cfg_sem yourself.
- */
-
-int ide_unregister_hwif(ide_hwif_t *hwif)
-{
- int ret;
-
- /* This protects two things. Firstly it serializes the
- shutdown sequence, secondly it protects us from
- races while we are killing off a device */
- down(&ide_cfg_sem);
- ret = __ide_unregister_hwif(hwif);
up(&ide_cfg_sem);
- return ret;
}
-EXPORT_SYMBOL_GPL(ide_unregister_hwif);
+EXPORT_SYMBOL(ide_unregister);
+
/**
* ide_setup_ports - set up IDE interface ports
* ide_register_hw_with_fixup - register IDE interface
* @hw: hardware registers
* @hwifp: pointer to returned hwif
- * @fixup function to call
+ * @fixup: fixup function
*
* Register an IDE interface, specifying exactly the registers etc.
- * Set init=1 iff calling before probes have taken place. The
- * ide_cfg_sem protects this against races.
- *
- * Invokes a fixup function after the probe and before device attachment
- * that can be used by the driver to amend settings or to work around
- * hardware funnies.
+ * Set init=1 iff calling before probes have taken place.
*
* Returns -1 on error.
*/
-int ide_register_hw_with_fixup(hw_regs_t *hw, ide_hwif_t **hwifp, void (*fixup)(ide_hwif_t *hwif))
+int ide_register_hw_with_fixup(hw_regs_t *hw, ide_hwif_t **hwifp, void(*fixup)(ide_hwif_t *hwif))
{
int index, retry = 1;
ide_hwif_t *hwif;
- down(&ide_cfg_sem);
-
do {
for (index = 0; index < MAX_HWIFS; ++index) {
hwif = &ide_hwifs[index];
hwif = &ide_hwifs[index];
if (hwif->hold)
continue;
- if ((!hwif->configured && !hwif->mate && !initializing) ||
+ if ((!hwif->present && !hwif->mate && !initializing) ||
(!hwif->hw.io_ports[IDE_DATA_OFFSET] && initializing))
goto found;
}
- /* FIXME- this check should die as should the retry loop */
for (index = 0; index < MAX_HWIFS; index++)
- {
- hwif = &ide_hwifs[index];
- __ide_unregister_hwif(hwif);
- }
+ ide_unregister(index);
} while (retry--);
-
- up(&ide_cfg_sem);
return -1;
found:
- /* FIXME: do we really need this case */
- if (hwif->configured)
- __ide_unregister_hwif(hwif);
+ if (hwif->present)
+ ide_unregister(index);
else if (!hwif->hold) {
init_hwif_data(hwif, index);
init_hwif_default(hwif, index);
}
- if (hwif->configured)
+ if (hwif->present)
return -1;
- hwif->configured = 1;
memcpy(&hwif->hw, hw, sizeof(*hw));
memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->hw.io_ports));
hwif->irq = hw->irq;
hwif->noprobe = 0;
hwif->chipset = hw->chipset;
- up(&ide_cfg_sem);
+ hwif->gendev.parent = hw->dev;
if (!initializing) {
probe_hwif_init_with_fixup(hwif, fixup);
EXPORT_SYMBOL(ide_register_hw_with_fixup);
-/**
- * ide_register_hw - register new IDE hardware
- * @hw: hardware registers
- * @hwifp: pointer to returned hwif
- *
- * Register an IDE interface, specifying exactly the registers etc.
- * Set init=1 iff calling before probes have taken place. The
- * ide_cfg_sem protects this against races.
- *
- * Returns -1 on error.
- */
-
-int ide_register_hw(hw_regs_t *hw, ide_hwif_t **hwif)
+int ide_register_hw(hw_regs_t *hw, ide_hwif_t **hwifp)
{
- return ide_register_hw_with_fixup(hw, hwif, NULL);
+ return ide_register_hw_with_fixup(hw, hwifp, NULL);
}
EXPORT_SYMBOL(ide_register_hw);
DECLARE_MUTEX(ide_setting_sem);
/**
- * ide_add_setting - add an ide setting option
+ * __ide_add_setting - add an ide setting option
* @drive: drive to use
* @name: setting name
* @rw: true if the function is read write
* @div_factor: divison scale
* @data: private data field
* @set: setting
+ * @auto_remove: setting auto removal flag
*
* Removes the setting named from the device if it is present.
- * This function must not be called from IRQ context. Returns 0
- * on success or -1 on failure.
+ * The function takes the settings_lock to protect against
+ * parallel changes. This function must not be called from IRQ
+ * context. Returns 0 on success or -1 on failure.
*
* BUGS: This code is seriously over-engineered. There is also
* magic about how the driver specific features are setup. If
* a driver is attached we assume the driver settings are auto
* remove.
- *
- * The caller must hold settings_lock
*/
-
-int ide_add_setting (ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set)
+
+static int __ide_add_setting(ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set, int auto_remove)
{
ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting = NULL;
+ down(&ide_setting_sem);
while ((*p) && strcmp((*p)->name, name) < 0)
p = &((*p)->next);
- if ((setting = kmalloc(sizeof(*setting), GFP_KERNEL)) == NULL)
+ if ((setting = kzalloc(sizeof(*setting), GFP_KERNEL)) == NULL)
goto abort;
- memset(setting, 0, sizeof(*setting));
if ((setting->name = kmalloc(strlen(name) + 1, GFP_KERNEL)) == NULL)
goto abort;
strcpy(setting->name, name);
setting->set = set;
setting->next = *p;
- if (drive->driver != &idedefault_driver)
+ if (auto_remove)
setting->auto_remove = 1;
*p = setting;
+ up(&ide_setting_sem);
return 0;
abort:
- if (setting)
- kfree(setting);
+ up(&ide_setting_sem);
+ kfree(setting);
return -1;
}
+int ide_add_setting(ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set)
+{
+ return __ide_add_setting(drive, name, rw, read_ioctl, write_ioctl, data_type, min, max, mul_factor, div_factor, data, set, 1);
+}
+
EXPORT_SYMBOL(ide_add_setting);
/**
- * ide_remove_setting - remove an ide setting option
+ * __ide_remove_setting - remove an ide setting option
* @drive: drive to use
* @name: setting name
*
* The caller must hold the setting semaphore.
*/
-static void ide_remove_setting (ide_drive_t *drive, char *name)
+static void __ide_remove_setting (ide_drive_t *drive, char *name)
{
ide_settings_t **p, *setting;
setting = drive->settings;
while (setting) {
if (setting->auto_remove) {
- ide_remove_setting(drive, setting->name);
+ __ide_remove_setting(drive, setting->name);
goto repeat;
}
setting = setting->next;
void ide_add_generic_settings (ide_drive_t *drive)
{
- down(&ide_setting_sem);
/*
- * drive setting name read/write access read ioctl write ioctl data type min max mul_factor div_factor data pointer set function
+ * drive setting name read/write access read ioctl write ioctl data type min max mul_factor div_factor data pointer set function
*/
- ide_add_setting(drive, "io_32bit", drive->no_io_32bit ? SETTING_READ : SETTING_RW, HDIO_GET_32BIT, HDIO_SET_32BIT, TYPE_BYTE, 0, 1 + (SUPPORT_VLB_SYNC << 1), 1, 1, &drive->io_32bit, set_io_32bit);
- ide_add_setting(drive, "keepsettings", SETTING_RW, HDIO_GET_KEEPSETTINGS, HDIO_SET_KEEPSETTINGS, TYPE_BYTE, 0, 1, 1, 1, &drive->keep_settings, NULL);
- ide_add_setting(drive, "nice1", SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->nice1, NULL);
- ide_add_setting(drive, "pio_mode", SETTING_WRITE, -1, HDIO_SET_PIO_MODE, TYPE_BYTE, 0, 255, 1, 1, NULL, set_pio_mode);
- ide_add_setting(drive, "unmaskirq", drive->no_unmask ? SETTING_READ : SETTING_RW, HDIO_GET_UNMASKINTR, HDIO_SET_UNMASKINTR, TYPE_BYTE, 0, 1, 1, 1, &drive->unmask, NULL);
- ide_add_setting(drive, "using_dma", SETTING_RW, HDIO_GET_DMA, HDIO_SET_DMA, TYPE_BYTE, 0, 1, 1, 1, &drive->using_dma, set_using_dma);
- ide_add_setting(drive, "init_speed", SETTING_RW, -1, -1, TYPE_BYTE, 0, 70, 1, 1, &drive->init_speed, NULL);
- ide_add_setting(drive, "current_speed", SETTING_RW, -1, -1, TYPE_BYTE, 0, 70, 1, 1, &drive->current_speed, set_xfer_rate);
- ide_add_setting(drive, "number", SETTING_RW, -1, -1, TYPE_BYTE, 0, 3, 1, 1, &drive->dn, NULL);
-
- up(&ide_setting_sem);
+ __ide_add_setting(drive, "io_32bit", drive->no_io_32bit ? SETTING_READ : SETTING_RW, HDIO_GET_32BIT, HDIO_SET_32BIT, TYPE_BYTE, 0, 1 + (SUPPORT_VLB_SYNC << 1), 1, 1, &drive->io_32bit, set_io_32bit, 0);
+ __ide_add_setting(drive, "keepsettings", SETTING_RW, HDIO_GET_KEEPSETTINGS, HDIO_SET_KEEPSETTINGS, TYPE_BYTE, 0, 1, 1, 1, &drive->keep_settings, NULL, 0);
+ __ide_add_setting(drive, "nice1", SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->nice1, NULL, 0);
+ __ide_add_setting(drive, "pio_mode", SETTING_WRITE, -1, HDIO_SET_PIO_MODE, TYPE_BYTE, 0, 255, 1, 1, NULL, set_pio_mode, 0);
+ __ide_add_setting(drive, "unmaskirq", drive->no_unmask ? SETTING_READ : SETTING_RW, HDIO_GET_UNMASKINTR, HDIO_SET_UNMASKINTR, TYPE_BYTE, 0, 1, 1, 1, &drive->unmask, NULL, 0);
+ __ide_add_setting(drive, "using_dma", SETTING_RW, HDIO_GET_DMA, HDIO_SET_DMA, TYPE_BYTE, 0, 1, 1, 1, &drive->using_dma, set_using_dma, 0);
+ __ide_add_setting(drive, "init_speed", SETTING_RW, -1, -1, TYPE_BYTE, 0, 70, 1, 1, &drive->init_speed, NULL, 0);
+ __ide_add_setting(drive, "current_speed", SETTING_RW, -1, -1, TYPE_BYTE, 0, 70, 1, 1, &drive->current_speed, set_xfer_rate, 0);
+ __ide_add_setting(drive, "number", SETTING_RW, -1, -1, TYPE_BYTE, 0, 3, 1, 1, &drive->dn, NULL, 0);
}
/**
EXPORT_SYMBOL(system_bus_clock);
-/*
- * Locking is badly broken here - since way back. That sucker is
- * root-only, but that's not an excuse... The real question is what
- * exclusion rules do we want here.
- */
-int ide_replace_subdriver (ide_drive_t *drive, const char *driver)
-{
- if (!drive->present || drive->usage || drive->dead)
- goto abort;
- if (DRIVER(drive)->cleanup(drive))
- goto abort;
- strlcpy(drive->driver_req, driver, sizeof(drive->driver_req));
- if (ata_attach(drive)) {
- spin_lock(&drives_lock);
- list_del_init(&drive->list);
- spin_unlock(&drives_lock);
- drive->driver_req[0] = 0;
- ata_attach(drive);
- } else {
- drive->driver_req[0] = 0;
- }
- if (DRIVER(drive)!= &idedefault_driver && !strcmp(DRIVER(drive)->name, driver))
- return 0;
-abort:
- return 1;
-}
-
-/**
- * ata_attach - attach an ATA/ATAPI device
- * @drive: drive to attach
- *
- * Takes a drive that is as yet not assigned to any midlayer IDE
- * driver (or is assigned to the default driver) and figures out
- * which driver would like to own it. If nobody claims the drive
- * then it is automatically attached to the default driver used for
- * unclaimed objects.
- *
- * A return of zero indicates attachment to a driver, of one
- * attachment to the default driver.
- *
- * Takes the driver list lock and the ide_settings semaphore.
- */
-
-int ata_attach(ide_drive_t *drive)
-{
- struct list_head *p;
- down(&drivers_sem);
- down(&ide_setting_sem);
- list_for_each(p, &drivers) {
- ide_driver_t *driver = list_entry(p, ide_driver_t, drivers);
- if (!try_module_get(driver->owner))
- continue;
- if (driver->attach(drive) == 0) {
- module_put(driver->owner);
- drive->gendev.driver = &driver->gen_driver;
- up(&ide_setting_sem);
- up(&drivers_sem);
- return 0;
- }
- module_put(driver->owner);
- }
- drive->gendev.driver = &idedefault_driver.gen_driver;
- up(&ide_setting_sem);
- up(&drivers_sem);
- if(idedefault_driver.attach(drive) != 0)
- panic("ide: default attach failed");
- return 1;
-}
-
-static int generic_ide_suspend(struct device *dev, u32 state)
+static int generic_ide_suspend(struct device *dev, pm_message_t state)
{
ide_drive_t *drive = dev->driver_data;
struct request rq;
rq.special = &args;
rq.pm = &rqpm;
rqpm.pm_step = ide_pm_state_start_suspend;
- rqpm.pm_state = state;
+ rqpm.pm_state = state.event;
return ide_do_drive_cmd(drive, &rq, ide_wait);
}
rq.special = &args;
rq.pm = &rqpm;
rqpm.pm_step = ide_pm_state_start_resume;
- rqpm.pm_state = 0;
+ rqpm.pm_state = PM_EVENT_ON;
return ide_do_drive_cmd(drive, &rq, ide_head_wait);
}
-int generic_ide_ioctl(struct file *file, struct block_device *bdev,
+int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device *bdev,
unsigned int cmd, unsigned long arg)
{
- ide_drive_t *drive = bdev->bd_disk->private_data;
ide_settings_t *setting;
+ ide_driver_t *drv;
int err = 0;
void __user *p = (void __user *)arg;
up(&ide_setting_sem);
switch (cmd) {
- case HDIO_GETGEO:
- {
- struct hd_geometry geom;
- if (!p || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL;
- geom.heads = drive->bios_head;
- geom.sectors = drive->bios_sect;
- geom.cylinders = (u16)drive->bios_cyl; /* truncate */
- geom.start = get_start_sect(bdev);
- if (copy_to_user(p, &geom, sizeof(struct hd_geometry)))
- return -EFAULT;
- return 0;
- }
-
case HDIO_OBSOLETE_IDENTITY:
case HDIO_GET_IDENTITY:
if (bdev != bdev->bd_contains)
case HDIO_SCAN_HWIF:
{
hw_regs_t hw;
- ide_hwif_t *hwif;
int args[3];
if (!capable(CAP_SYS_RAWIO)) return -EACCES;
if (copy_from_user(args, p, 3 * sizeof(int)))
ide_init_hwif_ports(&hw, (unsigned long) args[0],
(unsigned long) args[1], NULL);
hw.irq = args[2];
- if (ide_register_hw(&hw, &hwif) == -1)
+ if (ide_register_hw(&hw, NULL) == -1)
return -EIO;
- hwif->user_dev = 1;
return 0;
}
case HDIO_UNREGISTER_HWIF:
if (!capable(CAP_SYS_RAWIO)) return -EACCES;
- if(arg > MAX_HWIFS || arg < 0)
- return -EINVAL;
- if(!ide_hwifs[arg].user_dev)
- return -EINVAL;
- return ide_unregister_hwif(&ide_hwifs[arg]);
+ /* (arg > MAX_HWIFS) checked in function */
+ ide_unregister(arg);
return 0;
case HDIO_SET_NICE:
if (!capable(CAP_SYS_ADMIN)) return -EACCES;
if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP) | (1 << IDE_NICE_1))))
return -EPERM;
drive->dsc_overlap = (arg >> IDE_NICE_DSC_OVERLAP) & 1;
- if (drive->dsc_overlap && !DRIVER(drive)->supports_dsc_overlap) {
+ drv = *(ide_driver_t **)bdev->bd_disk->private_data;
+ if (drive->dsc_overlap && !drv->supports_dsc_overlap) {
drive->dsc_overlap = 0;
return -EPERM;
}
*/
spin_lock_irqsave(&ide_lock, flags);
-
- DRIVER(drive)->abort(drive, "drive reset");
+
+ ide_abort(drive, "drive reset");
+
if(HWGROUP(drive)->handler)
BUG();
HWGROUP(drive)->busy = 1;
spin_unlock_irqrestore(&ide_lock, flags);
(void) ide_do_reset(drive);
- if (drive->suspend_reset) {
-/*
- * APM WAKE UP todo !!
- * int nogoodpower = 1;
- * while(nogoodpower) {
- * check_power1() or check_power2()
- * nogoodpower = 0;
- * }
- * HWIF(drive)->multiproc(drive);
- */
- return ioctl_by_bdev(bdev, BLKRRPART, 0);
- }
+
return 0;
}
return 0; /* zero = nothing matched */
}
-#ifdef CONFIG_BLK_DEV_PDC4030
-static int __initdata probe_pdc4030;
-#endif
#ifdef CONFIG_BLK_DEV_ALI14XX
static int __initdata probe_ali14xx;
extern int ali14xx_init(void);
*
* Remember to update Documentation/ide.txt if you change something here.
*/
-int __init ide_setup (char *s)
+static int __init ide_setup(char *s)
{
int i, vals[3];
ide_hwif_t *hwif;
#endif /* CONFIG_BLK_DEV_IDEDOUBLER */
if (!strcmp(s, "ide=nodma")) {
- printk("IDE: Prevented DMA\n");
+ printk(" : Prevented DMA\n");
noautodma = 1;
return 1;
}
if (s[0] == 'h' && s[1] == 'd' && s[2] >= 'a' && s[2] <= max_drive) {
const char *hd_words[] = {
"none", "noprobe", "nowerr", "cdrom", "serialize",
- "autotune", "noautotune", "stroke", "swapdata", "bswap",
+ "autotune", "noautotune", "minus8", "swapdata", "bswap",
"minus11", "remap", "remap63", "scsi", NULL };
unit = s[2] - 'a';
hw = unit / MAX_DRIVES;
case -4: /* "cdrom" */
drive->present = 1;
drive->media = ide_cdrom;
+ /* an ATAPI device ignores DRDY */
+ drive->ready_stat = 0;
hwif->noprobe = 0;
goto done;
case -5: /* "serialize" */
goto do_serialize;
case -6: /* "autotune" */
drive->autotune = IDE_TUNE_AUTO;
- goto done;
+ goto obsolete_option;
case -7: /* "noautotune" */
drive->autotune = IDE_TUNE_NOAUTO;
- goto done;
- case -8: /* stroke */
- drive->stroke = 1;
- goto done;
+ goto obsolete_option;
case -9: /* "swapdata" */
case -10: /* "bswap" */
drive->bswap = 1;
goto done;
case 3: /* cyl,head,sect */
drive->media = ide_disk;
+ drive->ready_stat = READY_STAT;
drive->cyl = drive->bios_cyl = vals[0];
drive->head = drive->bios_head = vals[1];
drive->sect = drive->bios_sect = vals[2];
"noprobe", "serialize", "autotune", "noautotune",
"reset", "dma", "ata66", "minus8", "minus9",
"minus10", "four", "qd65xx", "ht6560b", "cmd640_vlb",
- "dtc2278", "umc8672", "ali14xx", "dc4030", NULL };
+ "dtc2278", "umc8672", "ali14xx", NULL };
hw = s[3] - '0';
hwif = &ide_hwifs[hw];
i = match_parm(&s[4], ide_words, vals, 3);
}
switch (i) {
-#ifdef CONFIG_BLK_DEV_PDC4030
- case -18: /* "dc4030" */
- probe_pdc4030 = 1;
- goto done;
-#endif
#ifdef CONFIG_BLK_DEV_ALI14XX
case -17: /* "ali14xx" */
probe_ali14xx = 1;
case -7: /* ata66 */
#ifdef CONFIG_BLK_DEV_IDEPCI
hwif->udma_four = 1;
- goto done;
+ goto obsolete_option;
#else
goto bad_hwif;
#endif
case -6: /* dma */
hwif->autodma = 1;
- goto done;
+ goto obsolete_option;
case -5: /* "reset" */
hwif->reset = 1;
- goto done;
+ goto obsolete_option;
case -4: /* "noautotune" */
hwif->drives[0].autotune = IDE_TUNE_NOAUTO;
hwif->drives[1].autotune = IDE_TUNE_NOAUTO;
- goto done;
+ goto obsolete_option;
case -3: /* "autotune" */
hwif->drives[0].autotune = IDE_TUNE_AUTO;
hwif->drives[1].autotune = IDE_TUNE_AUTO;
- goto done;
+ goto obsolete_option;
case -2: /* "serialize" */
do_serialize:
hwif->mate = &ide_hwifs[hw^1];
hwif->mate->mate = hwif;
hwif->serialized = hwif->mate->serialized = 1;
- goto done;
+ goto obsolete_option;
case -1: /* "noprobe" */
hwif->noprobe = 1;
hwif->irq = vals[2];
hwif->noprobe = 0;
hwif->chipset = ide_forced;
- goto done;
+ goto obsolete_option;
case 0: goto bad_option;
default:
bad_option:
printk(" -- BAD OPTION\n");
return 1;
+obsolete_option:
+ printk(" -- OBSOLETE OPTION, WILL BE REMOVED SOON!\n");
+ return 1;
bad_hwif:
printk("-- NOT SUPPORTED ON ide%d", hw);
done:
ide_probe_for_cmd640x();
}
#endif /* CONFIG_BLK_DEV_CMD640 */
-#ifdef CONFIG_BLK_DEV_PDC4030
- {
- extern int pdc4030_init(void);
- if (probe_pdc4030)
- (void)pdc4030_init();
- }
-#endif /* CONFIG_BLK_DEV_PDC4030 */
#ifdef CONFIG_BLK_DEV_IDE_PMAC
{
extern void pmac_ide_probe(void);
#endif
}
-/*
- * Actually unregister the subdriver. Called with the
- * request lock dropped.
- */
-
-static int default_cleanup (ide_drive_t *drive)
-{
- return ide_unregister_subdriver(drive);
-}
-
-static ide_startstop_t default_do_request (ide_drive_t *drive, struct request *rq, sector_t block)
+void ide_register_subdriver(ide_drive_t *drive, ide_driver_t *driver)
{
- ide_end_request(drive, 0, 0);
- return ide_stopped;
-}
-
-static int default_end_request (ide_drive_t *drive, int uptodate, int nr_sects)
-{
- return ide_end_request(drive, uptodate, nr_sects);
-}
-
-static u8 default_sense (ide_drive_t *drive, const char *msg, u8 stat)
-{
- return ide_dump_status(drive, msg, stat);
-}
-
-static ide_startstop_t default_error (ide_drive_t *drive, const char *msg, u8 stat)
-{
- return ide_error(drive, msg, stat);
-}
-
-static void default_pre_reset (ide_drive_t *drive)
-{
-}
-
-static sector_t default_capacity (ide_drive_t *drive)
-{
- return 0x7fffffff;
-}
-
-static ide_startstop_t default_special (ide_drive_t *drive)
-{
- special_t *s = &drive->special;
-
- s->all = 0;
- drive->mult_req = 0;
- return ide_stopped;
-}
-
-static int default_attach (ide_drive_t *drive)
-{
- printk(KERN_ERR "%s: does not support hotswap of device class !\n",
- drive->name);
-
- return 0;
-}
-
-static ide_startstop_t default_abort (ide_drive_t *drive, const char *msg)
-{
- return ide_abort(drive, msg);
-}
-
-static ide_startstop_t default_start_power_step(ide_drive_t *drive,
- struct request *rq)
-{
- rq->pm->pm_step = ide_pm_state_completed;
- return ide_stopped;
-}
-
-static void setup_driver_defaults (ide_driver_t *d)
-{
- if (d->cleanup == NULL) d->cleanup = default_cleanup;
- if (d->do_request == NULL) d->do_request = default_do_request;
- if (d->end_request == NULL) d->end_request = default_end_request;
- if (d->sense == NULL) d->sense = default_sense;
- if (d->error == NULL) d->error = default_error;
- if (d->abort == NULL) d->abort = default_abort;
- if (d->pre_reset == NULL) d->pre_reset = default_pre_reset;
- if (d->capacity == NULL) d->capacity = default_capacity;
- if (d->special == NULL) d->special = default_special;
- if (d->attach == NULL) d->attach = default_attach;
- if (d->start_power_step == NULL)
- d->start_power_step = default_start_power_step;
-}
-
-int ide_register_subdriver(ide_drive_t *drive, ide_driver_t *driver)
-{
- unsigned long flags;
-
- BUG_ON(!drive->driver);
-
- spin_lock_irqsave(&ide_lock, flags);
- if (!drive->present || drive->driver != &idedefault_driver ||
- drive->usage || drive->dead) {
- spin_unlock_irqrestore(&ide_lock, flags);
- return 1;
- }
- drive->driver = driver;
- spin_unlock_irqrestore(&ide_lock, flags);
- spin_lock(&drives_lock);
- list_add_tail(&drive->list, &driver->drives);
- spin_unlock(&drives_lock);
-// printk(KERN_INFO "%s: attached %s driver.\n", drive->name, driver->name);
- if ((drive->autotune == IDE_TUNE_DEFAULT) ||
- (drive->autotune == IDE_TUNE_AUTO)) {
- /* DMA timings and setup moved to ide-probe.c */
- drive->dsc_overlap = (drive->next != drive && driver->supports_dsc_overlap);
- drive->nice1 = 1;
- }
- drive->suspend_reset = 0;
#ifdef CONFIG_PROC_FS
- if (drive->driver != &idedefault_driver) {
- ide_add_proc_entries(drive->proc, generic_subdriver_entries, ide_drive_to_key(drive));
- ide_add_proc_entries(drive->proc, driver->proc, ide_drive_to_key(drive));
- }
+ ide_add_proc_entries(drive->proc, driver->proc, drive);
#endif
- return 0;
}
EXPORT_SYMBOL(ide_register_subdriver);
/**
* ide_unregister_subdriver - disconnect drive from driver
* @drive: drive to unplug
+ * @driver: driver
*
* Disconnect a drive from the driver it was attached to and then
* clean up the various proc files and other objects attached to it.
*
- * Takes ide_setting_sem, ide_lock and drives_lock.
+ * Takes ide_setting_sem and ide_lock.
* Caller must hold none of the locks.
- *
- * No locking versus subdriver unload because we are moving to the
- * default driver anyway. Wants double checking.
*/
-int ide_unregister_subdriver (ide_drive_t *drive)
+void ide_unregister_subdriver(ide_drive_t *drive, ide_driver_t *driver)
{
unsigned long flags;
- ide_proc_entry_t *dir;
down(&ide_setting_sem);
spin_lock_irqsave(&ide_lock, flags);
- if (drive->usage || drive->driver == &idedefault_driver || DRIVER(drive)->busy) {
- spin_unlock_irqrestore(&ide_lock, flags);
- up(&ide_setting_sem);
- return 1;
- }
- dir = DRIVER(drive)->proc;
- drive->driver = &idedefault_driver;
- spin_unlock_irqrestore(&ide_lock, flags);
#ifdef CONFIG_PROC_FS
- ide_remove_proc_entries(drive->proc, dir);
- ide_remove_proc_entries(drive->proc, generic_subdriver_entries);
+ ide_remove_proc_entries(drive->proc, driver->proc);
#endif
auto_remove_settings(drive);
+ spin_unlock_irqrestore(&ide_lock, flags);
up(&ide_setting_sem);
- spin_lock(&drives_lock);
- list_del_init(&drive->list);
- spin_unlock(&drives_lock);
- /* drive will be added to &idedefault_driver->drives in ata_attach() */
- return 0;
}
EXPORT_SYMBOL(ide_unregister_subdriver);
-static int ide_drive_remove(struct device * dev)
+/*
+ * Probe module
+ */
+
+EXPORT_SYMBOL(ide_lock);
+
+static int ide_bus_match(struct device *dev, struct device_driver *drv)
{
- ide_drive_t * drive = container_of(dev,ide_drive_t,gendev);
- DRIVER(drive)->cleanup(drive);
- return 0;
+ return 1;
}
-/**
- * ide_register_driver - register IDE device driver
- * @driver: the IDE device driver
- *
- * Register a new device driver and then scan the devices
- * on the IDE bus in case any should be attached to the
- * driver we have just registered. If so attach them.
- *
- * Takes the drivers and drives lock. Should take the
- * ide_sem but doesn't - FIXME ??
- */
-
-int ide_register_driver(ide_driver_t *driver)
+static char *media_string(ide_drive_t *drive)
{
- struct list_head list;
- struct list_head *list_loop;
- struct list_head *tmp_storage;
-
- setup_driver_defaults(driver);
-
- down(&drivers_sem);
- spin_lock(&drivers_lock);
- list_add(&driver->drivers, &drivers);
- spin_unlock(&drivers_lock);
- up(&drivers_sem);
-
- INIT_LIST_HEAD(&list);
- spin_lock(&drives_lock);
- list_splice_init(&idedefault_driver.drives, &list);
- spin_unlock(&drives_lock);
-
- list_for_each_safe(list_loop, tmp_storage, &list) {
- ide_drive_t *drive = container_of(list_loop, ide_drive_t, list);
- list_del_init(&drive->list);
- if (drive->present)
- ata_attach(drive);
+ switch (drive->media) {
+ case ide_disk:
+ return "disk";
+ case ide_cdrom:
+ return "cdrom";
+ case ide_tape:
+ return "tape";
+ case ide_floppy:
+ return "floppy";
+ default:
+ return "UNKNOWN";
}
- driver->gen_driver.name = (char *) driver->name;
- driver->gen_driver.bus = &ide_bus_type;
- driver->gen_driver.remove = ide_drive_remove;
- return driver_register(&driver->gen_driver);
}
-EXPORT_SYMBOL(ide_register_driver);
+static ssize_t media_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ ide_drive_t *drive = to_ide_device(dev);
+ return sprintf(buf, "%s\n", media_string(drive));
+}
-/**
- * ide_unregister_driver - unregister IDE device driver
- * @driver: the IDE device driver
- *
- * Called when a driver module is being unloaded. We reattach any
- * devices to whatever driver claims them next (typically the default
- * driver).
- *
- * Takes drivers_lock and called functions will take ide_setting_sem.
- */
+static ssize_t drivename_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ ide_drive_t *drive = to_ide_device(dev);
+ return sprintf(buf, "%s\n", drive->name);
+}
-void ide_unregister_driver(ide_driver_t *driver)
+static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf)
{
- ide_drive_t *drive;
+ ide_drive_t *drive = to_ide_device(dev);
+ return sprintf(buf, "ide:m-%s\n", media_string(drive));
+}
- down(&drivers_sem);
- spin_lock(&drivers_lock);
- list_del(&driver->drivers);
- spin_unlock(&drivers_lock);
- up(&drivers_sem);
+static struct device_attribute ide_dev_attrs[] = {
+ __ATTR_RO(media),
+ __ATTR_RO(drivename),
+ __ATTR_RO(modalias),
+ __ATTR_NULL
+};
- driver_unregister(&driver->gen_driver);
+static int ide_uevent(struct device *dev, char **envp, int num_envp,
+ char *buffer, int buffer_size)
+{
+ ide_drive_t *drive = to_ide_device(dev);
+ int i = 0;
+ int length = 0;
- while(!list_empty(&driver->drives)) {
- drive = list_entry(driver->drives.next, ide_drive_t, list);
- if (driver->cleanup(drive)) {
- printk(KERN_ERR "%s: cleanup_module() called while still busy\n", drive->name);
- BUG();
- }
- ata_attach(drive);
- }
+ add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
+ "MEDIA=%s", media_string(drive));
+ add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
+ "DRIVENAME=%s", drive->name);
+ add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
+ "MODALIAS=ide:m-%s", media_string(drive));
+ envp[i] = NULL;
+ return 0;
}
-EXPORT_SYMBOL(ide_unregister_driver);
+static int generic_ide_probe(struct device *dev)
+{
+ ide_drive_t *drive = to_ide_device(dev);
+ ide_driver_t *drv = to_ide_driver(dev->driver);
-struct block_device_operations ide_fops[] = {{
- .owner = THIS_MODULE,
- .open = ide_open,
-}};
+ return drv->probe ? drv->probe(drive) : -ENODEV;
+}
-EXPORT_SYMBOL(ide_fops);
+static int generic_ide_remove(struct device *dev)
+{
+ ide_drive_t *drive = to_ide_device(dev);
+ ide_driver_t *drv = to_ide_driver(dev->driver);
-/*
- * Probe module
- */
+ if (drv->remove)
+ drv->remove(drive);
-EXPORT_SYMBOL(ide_lock);
+ return 0;
+}
+
+static void generic_ide_shutdown(struct device *dev)
+{
+ ide_drive_t *drive = to_ide_device(dev);
+ ide_driver_t *drv = to_ide_driver(dev->driver);
+
+ if (dev->driver && drv->shutdown)
+ drv->shutdown(drive);
+}
struct bus_type ide_bus_type = {
.name = "ide",
+ .match = ide_bus_match,
+ .uevent = ide_uevent,
+ .probe = generic_ide_probe,
+ .remove = generic_ide_remove,
+ .shutdown = generic_ide_shutdown,
+ .dev_attrs = ide_dev_attrs,
.suspend = generic_ide_suspend,
.resume = generic_ide_resume,
};
+EXPORT_SYMBOL_GPL(ide_bus_type);
+
/*
* This is gets invoked once during initialization, to set *everything* up
*/
-int __init ide_init (void)
+static int __init ide_init(void)
{
printk(KERN_INFO "Uniform Multi-Platform E-IDE driver " REVISION "\n");
devfs_mk_dir("ide");
}
#ifdef MODULE
-char *options = NULL;
-MODULE_PARM(options,"s");
+static char *options = NULL;
+module_param(options, charp, 0);
MODULE_LICENSE("GPL");
static void __init parse_options (char *line)
{
int index;
- for (index = 0; index < MAX_HWIFS; ++index) {
- if(ide_unregister_hwif(&ide_hwifs[index]))
- printk(KERN_ERR "ide: unload yet busy!\n");
- if (ide_hwifs[index].dma_base)
- (void) ide_release_dma(&ide_hwifs[index]);
- }
+ for (index = 0; index < MAX_HWIFS; ++index)
+ ide_unregister(index);
#ifdef CONFIG_PROC_FS
proc_ide_destroy();