📄 ide.c
字号:
* This function issues a special IDE device request * onto the request queue. * * If action is ide_wait, then the rq is queued at the end of the * request queue, and the function sleeps until it has been processed. * This is for use when invoked from an ioctl handler. * * If action is ide_preempt, then the rq is queued at the head of * the request queue, displacing the currently-being-processed * request and this function returns immediately without waiting * for the new rq to be completed. This is VERY DANGEROUS, and is * intended for careful use by the ATAPI tape/cdrom driver code. * * If action is ide_next, then the rq is queued immediately after * the currently-being-processed-request (if any), and the function * returns without waiting for the new rq to be completed. As above, * This is VERY DANGEROUS, and is intended for careful use by the * ATAPI tape/cdrom driver code. * * If action is ide_end, then the rq is queued at the end of the * request queue, and the function returns immediately without waiting * for the new rq to be completed. This is again intended for careful * use by the ATAPI tape/cdrom driver code. */int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t action){ unsigned long flags; ide_hwgroup_t *hwgroup = HWGROUP(drive); unsigned int major = HWIF(drive)->major; struct list_head * queue_head; DECLARE_MUTEX_LOCKED(sem);#ifdef CONFIG_BLK_DEV_PDC4030 if (HWIF(drive)->chipset == ide_pdc4030 && rq->buffer != NULL) return -ENOSYS; /* special drive cmds not supported */#endif rq->errors = 0; rq->rq_status = RQ_ACTIVE; rq->rq_dev = MKDEV(major,(drive->select.b.unit)<<PARTN_BITS); if (action == ide_wait) rq->sem = &sem; spin_lock_irqsave(&io_request_lock, flags); queue_head = &drive->queue.queue_head; if (list_empty(queue_head) || action == ide_preempt) { if (action == ide_preempt) hwgroup->rq = NULL; } else { if (action == ide_wait || action == ide_end) { queue_head = queue_head->prev; } else queue_head = queue_head->next; } list_add(&rq->queue, queue_head); ide_do_request(hwgroup, 0); spin_unlock_irqrestore(&io_request_lock, flags); if (action == ide_wait) { down(&sem); /* wait for it to be serviced */ return rq->errors ? -EIO : 0; /* return -EIO if errors */ } return 0;}/* * This routine is called to flush all partitions and partition tables * for a changed disk, and then re-read the new partition table. * If we are revalidating a disk because of a media change, then we * enter with usage == 0. If we are using an ioctl, we automatically have * usage == 1 (we need an open channel to use an ioctl :-), so this * is our limit. */int ide_revalidate_disk (kdev_t i_rdev){ ide_drive_t *drive; ide_hwgroup_t *hwgroup; unsigned int p, major, minor; long flags; if ((drive = get_info_ptr(i_rdev)) == NULL) return -ENODEV; major = MAJOR(i_rdev); minor = drive->select.b.unit << PARTN_BITS; hwgroup = HWGROUP(drive); spin_lock_irqsave(&io_request_lock, flags); if (drive->busy || (drive->usage > 1)) { spin_unlock_irqrestore(&io_request_lock, flags); return -EBUSY; }; drive->busy = 1; MOD_INC_USE_COUNT; spin_unlock_irqrestore(&io_request_lock, flags); for (p = 0; p < (1<<PARTN_BITS); ++p) { if (drive->part[p].nr_sects > 0) { kdev_t devp = MKDEV(major, minor+p); struct super_block * sb = get_super(devp); fsync_dev (devp); if (sb) invalidate_inodes(sb); invalidate_buffers (devp); set_blocksize(devp, 1024); } drive->part[p].start_sect = 0; drive->part[p].nr_sects = 0; }; if (DRIVER(drive)->revalidate) DRIVER(drive)->revalidate(drive); drive->busy = 0; wake_up(&drive->wqueue); MOD_DEC_USE_COUNT; return 0;}static void revalidate_drives (void){ ide_hwif_t *hwif; ide_drive_t *drive; int index, unit; for (index = 0; index < MAX_HWIFS; ++index) { hwif = &ide_hwifs[index]; for (unit = 0; unit < MAX_DRIVES; ++unit) { drive = &ide_hwifs[index].drives[unit]; if (drive->revalidate) { drive->revalidate = 0; if (!initializing) (void) ide_revalidate_disk(MKDEV(hwif->major, unit<<PARTN_BITS)); } } }}static void ide_probe_module (void){ if (!ide_probe) {#if defined(CONFIG_KMOD) && defined(CONFIG_BLK_DEV_IDE_MODULE) (void) request_module("ide-probe-mod");#endif /* (CONFIG_KMOD) && (CONFIG_BLK_DEV_IDE_MODULE) */ } else { (void) ide_probe->init(); } revalidate_drives();}static void ide_driver_module (void){ int index; ide_module_t *module = ide_modules; for (index = 0; index < MAX_HWIFS; ++index) if (ide_hwifs[index].present) goto search; ide_probe_module();search: while (module) { (void) module->init(); module = module->next; } revalidate_drives();}static int ide_open (struct inode * inode, struct file * filp){ ide_drive_t *drive; int rc; if ((drive = get_info_ptr(inode->i_rdev)) == NULL) return -ENXIO; MOD_INC_USE_COUNT; if (drive->driver == NULL) ide_driver_module();#ifdef CONFIG_KMOD if (drive->driver == NULL) { if (drive->media == ide_disk) (void) request_module("ide-disk"); if (drive->media == ide_cdrom) (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"); }#endif /* CONFIG_KMOD */ while (drive->busy) sleep_on(&drive->wqueue); drive->usage++; if (drive->driver != NULL) { if ((rc = DRIVER(drive)->open(inode, filp, drive))) MOD_DEC_USE_COUNT; return rc; } printk ("%s: driver not present\n", drive->name); drive->usage--; MOD_DEC_USE_COUNT; return -ENXIO;}/* * Releasing a block device means we sync() it, so that it can safely * be forgotten about... */static int ide_release (struct inode * inode, struct file * file){ ide_drive_t *drive; if ((drive = get_info_ptr(inode->i_rdev)) != NULL) { drive->usage--; if (drive->driver != NULL) DRIVER(drive)->release(inode, file, drive); MOD_DEC_USE_COUNT; } return 0;}int ide_replace_subdriver (ide_drive_t *drive, const char *driver){ if (!drive->present || drive->busy || drive->usage) goto abort; if (drive->driver != NULL && DRIVER(drive)->cleanup(drive)) goto abort; strncpy(drive->driver_req, driver, 9); ide_driver_module(); drive->driver_req[0] = 0; ide_driver_module(); if (DRIVER(drive) && !strcmp(DRIVER(drive)->name, driver)) return 0;abort: return 1;}#ifdef CONFIG_PROC_FSide_proc_entry_t generic_subdriver_entries[] = { { "capacity", S_IFREG|S_IRUGO, proc_ide_read_capacity, NULL }, { NULL, 0, NULL, NULL }};#endif/* * Note that we only release the standard ports, * and do not even try to handle any extra ports * allocated for weird IDE interface chipsets. */void hwif_unregister (ide_hwif_t *hwif){ if (hwif->straight8) { ide_release_region(hwif->io_ports[IDE_DATA_OFFSET], 8); goto jump_eight; } if (hwif->io_ports[IDE_DATA_OFFSET]) ide_release_region(hwif->io_ports[IDE_DATA_OFFSET], 1); if (hwif->io_ports[IDE_ERROR_OFFSET]) ide_release_region(hwif->io_ports[IDE_ERROR_OFFSET], 1); if (hwif->io_ports[IDE_NSECTOR_OFFSET]) ide_release_region(hwif->io_ports[IDE_NSECTOR_OFFSET], 1); if (hwif->io_ports[IDE_SECTOR_OFFSET]) ide_release_region(hwif->io_ports[IDE_SECTOR_OFFSET], 1); if (hwif->io_ports[IDE_LCYL_OFFSET]) ide_release_region(hwif->io_ports[IDE_LCYL_OFFSET], 1); if (hwif->io_ports[IDE_HCYL_OFFSET]) ide_release_region(hwif->io_ports[IDE_HCYL_OFFSET], 1); if (hwif->io_ports[IDE_SELECT_OFFSET]) ide_release_region(hwif->io_ports[IDE_SELECT_OFFSET], 1); if (hwif->io_ports[IDE_STATUS_OFFSET]) ide_release_region(hwif->io_ports[IDE_STATUS_OFFSET], 1);jump_eight: if (hwif->io_ports[IDE_CONTROL_OFFSET]) ide_release_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1);#if defined(CONFIG_AMIGA) || defined(CONFIG_MAC) if (hwif->io_ports[IDE_IRQ_OFFSET]) ide_release_region(hwif->io_ports[IDE_IRQ_OFFSET], 1);#endif /* (CONFIG_AMIGA) || (CONFIG_MAC) */}void ide_unregister (unsigned int index){ struct gendisk *gd, **gdp; ide_drive_t *drive, *d; ide_hwif_t *hwif, *g; ide_hwgroup_t *hwgroup; int irq_count = 0, unit, i; unsigned long flags; unsigned int p, minor; ide_hwif_t old_hwif; if (index >= MAX_HWIFS) return; save_flags(flags); /* all CPUs */ cli(); /* all CPUs */ hwif = &ide_hwifs[index]; if (!hwif->present) goto abort; for (unit = 0; unit < MAX_DRIVES; ++unit) { drive = &hwif->drives[unit]; if (!drive->present) continue; if (drive->busy || drive->usage) goto abort; if (drive->driver != NULL && DRIVER(drive)->cleanup(drive)) goto abort; } hwif->present = 0; /* * All clear? Then blow away the buffer cache */ sti(); for (unit = 0; unit < MAX_DRIVES; ++unit) { drive = &hwif->drives[unit]; if (!drive->present) continue; minor = drive->select.b.unit << PARTN_BITS; for (p = 0; p < (1<<PARTN_BITS); ++p) { if (drive->part[p].nr_sects > 0) { kdev_t devp = MKDEV(hwif->major, minor+p); struct super_block * sb = get_super(devp); if (sb) invalidate_inodes(sb); invalidate_buffers (devp); } }#ifdef CONFIG_PROC_FS destroy_proc_ide_drives(hwif);#endif } cli(); hwgroup = hwif->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); /* * Note that we only release the standard ports, * and do not even try to handle any extra ports * allocated for weird IDE interface chipsets. */ hwif_unregister(hwif); /* * Remove us from the hwgroup, and free * the hwgroup if we were the only member */ d = hwgroup->drive; for (i = 0; i < MAX_DRIVES; ++i) { drive = &hwif->drives[i]; if (drive->de) { devfs_unregister (drive->de); drive->de = NULL; } if (!drive->present) continue; while (hwgroup->drive->next != drive) hwgroup->drive = hwgroup->drive->next; hwgroup->drive->next = drive->next; if (hwgroup->drive == drive) hwgroup->drive = NULL; if (drive->id != NULL) { kfree(drive->id); drive->id = NULL; } drive->present = 0; blk_cleanup_queue(&drive->queue); } if (d->present) hwgroup->drive = d; while (hwgroup->hwif->next != hwif) hwgroup->hwif = hwgroup->hwif->next; hwgroup->hwif->next = hwif->next; if (hwgroup->hwif == hwif) kfree(hwgroup); else hwgroup->hwif = HWIF(hwgroup->drive);#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI) if (hwif->dma_base) { (void) ide_release_dma(hwif); hwif->dma_base = 0; }#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */ /* * Remove us from the kernel's knowledge */ unregister_blkdev(hwif->major, hwif->name); kfree(blksize_size[hwif->major]); kfree(max_sectors[hwif->major]); kfree(max_readahead[hwif->major]); blk_dev[hwif->major].data = NULL; blk_dev[hwif->major].queue = NULL; blksize_size[hwif->major] = NULL; for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next)) if (*gdp == hwif->gd) break; if (*gdp == NULL) printk("gd not in disk chain!\n"); else { gd = *gdp; *gdp = gd->next; kfree(gd->sizes); kfree(gd->part); if (gd->de_arr) kfree (gd->de_arr); if (gd->flags) kfree (gd->flags); kfree(gd); } old_hwif = *hwif; init_hwif_data (index); /* r
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -