#endif
}
-/*
- * ide_system_bus_speed() returns what we think is the system VESA/PCI
- * bus speed (in MHz). This is used for calculating interface PIO timings.
- * The default is 40 for known PCI systems, 50 otherwise.
- * The "idebus=xx" parameter can be used to override this value.
- * The actual value to be used is computed/displayed the first time through.
+/**
+ * ide_system_bus_speed - guess bus speed
+ *
+ * ide_system_bus_speed() returns what we think is the system VESA/PCI
+ * bus speed (in MHz). This is used for calculating interface PIO timings.
+ * The default is 40 for known PCI systems, 50 otherwise.
+ * The "idebus=xx" parameter can be used to override this value.
+ * The actual value to be used is computed/displayed the first time
+ * through. Drivers should only use this as a last resort.
+ *
+ * Returns a guessed speed in MHz.
*/
+
int ide_system_bus_speed (void)
{
if (!system_bus_speed) {
return system_bus_speed;
}
-/*
- * current_capacity() returns the capacity (in sectors) of a drive
- * according to its current geometry/LBA settings.
+/**
+ * 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)
EXPORT_SYMBOL(current_capacity);
-/*
- * Error reporting, in human readable form (luxurious, but a memory hog).
+/**
+ * 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);
local_irq_set(flags);
printk(KERN_WARNING "%s: %s: status=0x%02x", drive->name, msg, stat);
-#if FANCY_STATUS_DUMPS
printk(" { ");
if (stat & BUSY_STAT) {
printk("Busy ");
if (stat & ERR_STAT) printk("Error ");
}
printk("}");
-#endif /* FANCY_STATUS_DUMPS */
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 FANCY_STATUS_DUMPS
if (drive->media == ide_disk) {
printk(" { ");
if (err & ABRT_ERR) printk("DriveStatusError ");
printk(", sector=%llu", (unsigned long long)HWGROUP(drive)->rq->sector);
}
}
-#endif /* FANCY_STATUS_DUMPS */
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;
}
return -ENXIO;
}
+/*
+ * drives_lock protects the list of drives, drivers_lock the
+ * list of drivers. Currently nobody takes both at once.
+ */
+
static spinlock_t drives_lock = SPIN_LOCK_UNLOCKED;
static spinlock_t drivers_lock = SPIN_LOCK_UNLOCKED;
static LIST_HEAD(drivers);
-/* Iterator */
+/* Iterator for the driver list. */
+
static void *m_start(struct seq_file *m, loff_t *pos)
{
struct list_head *p;
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)
{
spin_unlock(&drivers_lock);
}
+
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,
* MMIO leaves it to the controller driver,
* PIO will migrate this way over time.
*/
+
int ide_hwif_request_regions(ide_hwif_t *hwif)
{
unsigned long addr;
* importantly our caller should be doing this so we need to
* restructure this as a helper function for drivers.
*/
+
void ide_hwif_release_regions(ide_hwif_t *hwif)
{
u32 i = 0;
release_region(hwif->io_ports[i], 1);
}
-/* restore hwif to a sane state */
+/**
+ * ide_hwif_restore - restore hwif to template
+ * @hwif: hwif to update
+ * @tmp_hwif: template
+ *
+ * Restore hwif to a previous state by copying most settngs
+ * from the template.
+ */
+
static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
{
hwif->hwgroup = tmp_hwif->hwgroup;
void ide_unregister(unsigned int index)
{
ide_drive_t *drive;
- ide_hwif_t *hwif, *g, *tmp_hwif;
+ 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;
BUG_ON(index >= MAX_HWIFS);
- tmp_hwif = kmalloc(sizeof(*tmp_hwif), GFP_KERNEL|__GFP_NOFAIL);
- if (!tmp_hwif) {
- printk(KERN_ERR "%s: unable to allocate memory\n", __FUNCTION__);
- return;
- }
-
BUG_ON(in_interrupt());
BUG_ON(irqs_disabled());
down(&ide_cfg_sem);
}
/* copy original settings */
- *tmp_hwif = *hwif;
+ tmp_hwif = *hwif;
/* restore hwif data to pristine status */
init_hwif_data(hwif, index);
init_hwif_default(hwif, index);
- ide_hwif_restore(hwif, tmp_hwif);
+ ide_hwif_restore(hwif, &tmp_hwif);
abort:
spin_unlock_irq(&ide_lock);
up(&ide_cfg_sem);
-
- kfree(tmp_hwif);
}
EXPORT_SYMBOL(ide_unregister);
*/
}
-/*
- * Register an IDE interface, specifying exactly the registers etc
- * Set init=1 iff calling before probes have taken place.
+/**
+ * ide_register_hw - register IDE interface
+ * @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.
+ *
+ * Returns -1 on error.
*/
+
int ide_register_hw (hw_regs_t *hw, ide_hwif_t **hwifp)
{
int index, retry = 1;
return val;
}
+/**
+ * ide_spin_wait_hwgroup - wait for group
+ * @drive: drive in the group
+ *
+ * Wait for an IDE device group to go non busy and then return
+ * holding the ide_lock which guards the hwgroup->busy status
+ * and right to use it.
+ */
+
int ide_spin_wait_hwgroup (ide_drive_t *drive)
{
ide_hwgroup_t *hwgroup = HWGROUP(drive);
* to the driver to change settings, and then wait on a sema for completion.
* The current scheme of polling is kludgy, though safe enough.
*/
+
int ide_write_setting (ide_drive_t *drive, ide_settings_t *setting, int val)
{
int i;
return err;
}
-int ide_atapi_to_scsi (ide_drive_t *drive, int arg)
-{
- if (drive->media == ide_disk) {
- drive->scsi = 0;
- return 0;
- }
-
- if (DRIVER(drive)->cleanup(drive)) {
- drive->scsi = 0;
- return 0;
- }
-
- drive->scsi = (u8) arg;
- ata_attach(drive);
- return 0;
-}
+/**
+ * ide_add_generic_settings - generic ide settings
+ * @drive: drive being configured
+ *
+ * Add the generic parts of the system settings to the /proc files and
+ * ioctls for this IDE device. The caller must not be holding the
+ * ide_setting_sem.
+ */
void ide_add_generic_settings (ide_drive_t *drive)
{
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);
- if (drive->media != ide_disk)
- ide_add_setting(drive, "ide-scsi", SETTING_RW, -1, HDIO_SET_IDE_SCSI, TYPE_BYTE, 0, 1, 1, 1, &drive->scsi, ide_atapi_to_scsi);
}
+/**
+ * system_bus_clock - clock guess
+ *
+ * External version of the bus clock guess used by very old IDE drivers
+ * for things like VLB timings. Should not be used.
+ */
+
int system_bus_clock (void)
{
return((int) ((!system_bus_speed) ? ide_system_bus_speed() : system_bus_speed ));
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 drivers_lock.
+ */
+
int ata_attach(ide_drive_t *drive)
{
struct list_head *p;
EXPORT_SYMBOL(ide_register_subdriver);
+/**
+ * ide_unregister_subdriver - disconnect drive from driver
+ * @drive: drive to unplug
+ *
+ * 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.
+ * 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)
{
unsigned long flags;
return 0;
}
+/**
+ * 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 drivers_lock and drives_lock.
+ */
+
int ide_register_driver(ide_driver_t *driver)
{
struct list_head list;
EXPORT_SYMBOL(ide_register_driver);
+/**
+ * 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.
+ */
+
void ide_unregister_driver(ide_driver_t *driver)
{
ide_drive_t *drive;