|
@@ -918,6 +918,8 @@ static int ide_init_queue(ide_drive_t *drive)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static DEFINE_MUTEX(ide_cfg_mtx);
|
|
|
+
|
|
|
/*
|
|
|
* For any present drive:
|
|
|
* - allocate the block device queue
|
|
@@ -1273,6 +1275,69 @@ static void ide_port_cable_detect(ide_hwif_t *hwif)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static const u8 ide_hwif_to_major[] =
|
|
|
+ { IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR, IDE4_MAJOR,
|
|
|
+ IDE5_MAJOR, IDE6_MAJOR, IDE7_MAJOR, IDE8_MAJOR, IDE9_MAJOR };
|
|
|
+
|
|
|
+static void ide_port_init_devices_data(ide_hwif_t *hwif)
|
|
|
+{
|
|
|
+ int unit;
|
|
|
+
|
|
|
+ for (unit = 0; unit < MAX_DRIVES; ++unit) {
|
|
|
+ ide_drive_t *drive = &hwif->drives[unit];
|
|
|
+ u8 j = (hwif->index * MAX_DRIVES) + unit;
|
|
|
+
|
|
|
+ memset(drive, 0, sizeof(*drive));
|
|
|
+
|
|
|
+ drive->media = ide_disk;
|
|
|
+ drive->select = (unit << 4) | ATA_DEVICE_OBS;
|
|
|
+ drive->hwif = hwif;
|
|
|
+ drive->ready_stat = ATA_DRDY;
|
|
|
+ drive->bad_wstat = BAD_W_STAT;
|
|
|
+ drive->special.b.recalibrate = 1;
|
|
|
+ drive->special.b.set_geometry = 1;
|
|
|
+ drive->name[0] = 'h';
|
|
|
+ drive->name[1] = 'd';
|
|
|
+ drive->name[2] = 'a' + j;
|
|
|
+ drive->max_failures = IDE_DEFAULT_MAX_FAILURES;
|
|
|
+
|
|
|
+ INIT_LIST_HEAD(&drive->list);
|
|
|
+ init_completion(&drive->gendev_rel_comp);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void ide_init_port_data(ide_hwif_t *hwif, unsigned int index)
|
|
|
+{
|
|
|
+ /* bulk initialize hwif & drive info with zeros */
|
|
|
+ memset(hwif, 0, sizeof(ide_hwif_t));
|
|
|
+
|
|
|
+ /* fill in any non-zero initial values */
|
|
|
+ hwif->index = index;
|
|
|
+ hwif->major = ide_hwif_to_major[index];
|
|
|
+
|
|
|
+ hwif->name[0] = 'i';
|
|
|
+ hwif->name[1] = 'd';
|
|
|
+ hwif->name[2] = 'e';
|
|
|
+ hwif->name[3] = '0' + index;
|
|
|
+
|
|
|
+ init_completion(&hwif->gendev_rel_comp);
|
|
|
+
|
|
|
+ hwif->tp_ops = &default_tp_ops;
|
|
|
+
|
|
|
+ ide_port_init_devices_data(hwif);
|
|
|
+}
|
|
|
+
|
|
|
+static void ide_init_port_hw(ide_hwif_t *hwif, hw_regs_t *hw)
|
|
|
+{
|
|
|
+ memcpy(&hwif->io_ports, &hw->io_ports, sizeof(hwif->io_ports));
|
|
|
+ hwif->irq = hw->irq;
|
|
|
+ hwif->chipset = hw->chipset;
|
|
|
+ hwif->dev = hw->dev;
|
|
|
+ hwif->gendev.parent = hw->parent ? hw->parent : hw->dev;
|
|
|
+ hwif->ack_intr = hw->ack_intr;
|
|
|
+ hwif->config_data = hw->config;
|
|
|
+}
|
|
|
+
|
|
|
static unsigned int ide_indexes;
|
|
|
|
|
|
/**
|
|
@@ -1503,6 +1568,76 @@ int ide_host_add(const struct ide_port_info *d, hw_regs_t **hws,
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(ide_host_add);
|
|
|
|
|
|
+static void __ide_port_unregister_devices(ide_hwif_t *hwif)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for (i = 0; i < MAX_DRIVES; i++) {
|
|
|
+ ide_drive_t *drive = &hwif->drives[i];
|
|
|
+
|
|
|
+ if (drive->dev_flags & IDE_DFLAG_PRESENT) {
|
|
|
+ device_unregister(&drive->gendev);
|
|
|
+ wait_for_completion(&drive->gendev_rel_comp);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void ide_port_unregister_devices(ide_hwif_t *hwif)
|
|
|
+{
|
|
|
+ mutex_lock(&ide_cfg_mtx);
|
|
|
+ __ide_port_unregister_devices(hwif);
|
|
|
+ hwif->present = 0;
|
|
|
+ ide_port_init_devices_data(hwif);
|
|
|
+ mutex_unlock(&ide_cfg_mtx);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(ide_port_unregister_devices);
|
|
|
+
|
|
|
+/**
|
|
|
+ * ide_unregister - free an IDE interface
|
|
|
+ * @hwif: IDE interface
|
|
|
+ *
|
|
|
+ * Perform the final unregister of an IDE interface.
|
|
|
+ *
|
|
|
+ * Locking:
|
|
|
+ * The caller must not hold the IDE locks.
|
|
|
+ *
|
|
|
+ * It is up to the caller to be sure there is no pending I/O here,
|
|
|
+ * and that the interface will not be reopened (present/vanishing
|
|
|
+ * locking isn't yet done BTW).
|
|
|
+ */
|
|
|
+
|
|
|
+static void ide_unregister(ide_hwif_t *hwif)
|
|
|
+{
|
|
|
+ BUG_ON(in_interrupt());
|
|
|
+ BUG_ON(irqs_disabled());
|
|
|
+
|
|
|
+ mutex_lock(&ide_cfg_mtx);
|
|
|
+
|
|
|
+ if (hwif->present) {
|
|
|
+ __ide_port_unregister_devices(hwif);
|
|
|
+ hwif->present = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ ide_proc_unregister_port(hwif);
|
|
|
+
|
|
|
+ free_irq(hwif->irq, hwif);
|
|
|
+
|
|
|
+ device_unregister(hwif->portdev);
|
|
|
+ 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);
|
|
|
+ kfree(hwif->sg_table);
|
|
|
+ unregister_blkdev(hwif->major, hwif->name);
|
|
|
+
|
|
|
+ ide_release_dma_engine(hwif);
|
|
|
+
|
|
|
+ mutex_unlock(&ide_cfg_mtx);
|
|
|
+}
|
|
|
+
|
|
|
void ide_host_free(struct ide_host *host)
|
|
|
{
|
|
|
ide_hwif_t *hwif;
|