📄 ide.c
字号:
((ide_hwgroup_t *)hwif->hwgroup)->drive = drive;#if (DISK_RECOVERY_TIME > 0) while ((read_timer() - hwif->last_time) < DISK_RECOVERY_TIME);#endif#ifdef CONFIG_BLK_DEV_IDETAPE POLL_HWIF_TAPE_DRIVE; /* macro from ide-tape.h */#endif /* CONFIG_BLK_DEV_IDETAPE */ SELECT_DRIVE(hwif,drive); if (ide_wait_stat(drive, drive->ready_stat, BUSY_STAT|DRQ_STAT, WAIT_READY)) { printk("%s: drive not ready for command\n", drive->name); return; } if (!drive->special.all) { if (rq->cmd == IDE_DRIVE_CMD) { execute_drive_cmd(drive, rq); return; }#ifdef CONFIG_BLK_DEV_IDEATAPI switch (drive->media) { case ide_disk: do_rw_disk (drive, rq, block); return;#ifdef CONFIG_BLK_DEV_IDECD case ide_cdrom: ide_do_rw_cdrom (drive, block); return;#endif /* CONFIG_BLK_DEV_IDECD */#ifdef CONFIG_BLK_DEV_IDETAPE case ide_tape: idetape_do_request (drive, rq, block); return;#endif /* CONFIG_BLK_DEV_IDETAPE */#ifdef CONFIG_BLK_DEV_IDEFLOPPY case ide_floppy: idefloppy_do_request (drive, rq, block); return;#endif /* CONFIG_BLK_DEV_IDEFLOPPY */#ifdef CONFIG_BLK_DEV_IDESCSI case ide_scsi: idescsi_do_request (drive, rq, block); return;#endif /* CONFIG_BLK_DEV_IDESCSI */ default: printk("%s: media type %d not supported\n", drive->name, drive->media); goto kill_rq; }#else do_rw_disk (drive, rq, block); /* simpler and faster */ return;#endif /* CONFIG_BLK_DEV_IDEATAPI */ } do_special(drive); return;kill_rq: ide_end_request(0, hwif->hwgroup);}/* * The driver enables interrupts as much as possible. In order to do this, * (a) the device-interrupt is always masked before entry, and * (b) the timeout-interrupt is always disabled before entry. * * If we enter here from, say irq14, and then start a new request for irq15, * (possible with "serialize" option) then we cannot ensure that we exit * before the irq15 hits us. So, we must be careful not to let this bother us. * * Interrupts are still masked (by default) whenever we are exchanging * data/cmds with a drive, because some drives seem to have very poor * tolerance for latency during I/O. For devices which don't suffer from * this problem (most don't), the unmask flag can be set using the "hdparm" * utility, to permit other interrupts during data/cmd transfers. */void ide_do_request (ide_hwgroup_t *hwgroup){ cli(); /* paranoia */ if (hwgroup->handler != NULL) { printk("%s: EEeekk!! handler not NULL in ide_do_request()\n", hwgroup->hwif->name); return; } do { ide_hwif_t *hwif = hwgroup->hwif; struct request *rq; if ((rq = hwgroup->rq) == NULL) { if (hwif->sharing_irq && hwgroup->drive) /* set nIEN */ OUT_BYTE(hwgroup->drive->ctl|2,hwif->ctl_port); /* * hwgroup->next_hwif is different from hwgroup->hwif * only when a request is inserted using "ide_next". * This saves wear and tear on IDE tapes. */ hwif = hwgroup->next_hwif; do { rq = blk_dev[hwif->major].current_request; if (rq != NULL && rq->rq_status != RQ_INACTIVE) goto got_rq; } while ((hwif = hwif->next) != hwgroup->next_hwif); hwgroup->active = 0; return; /* no work left for this hwgroup */ } got_rq: do_request(hwgroup->hwif = hwgroup->next_hwif = hwif, hwgroup->rq = rq); cli(); } while (hwgroup->handler == NULL);}/* * do_hwgroup_request() invokes ide_do_request() after first masking * all possible interrupts for the current hwgroup. This prevents race * conditions in the event that an unexpected interrupt occurs while * we are in the driver. * * Note that when an interrupt is used to reenter the driver, the first level * handler will already have masked the irq that triggered, but any other ones * for the hwgroup will still be unmasked. The driver tries to be careful * about such things. */static void do_hwgroup_request (ide_hwgroup_t *hwgroup){ if (hwgroup->handler == NULL) { ide_hwif_t *hgif = hwgroup->hwif; ide_hwif_t *hwif = hgif; hwgroup->active = 1; do { disable_irq(hwif->irq); } while ((hwif = hwif->next) != hgif); ide_do_request (hwgroup); do { enable_irq(hwif->irq); } while ((hwif = hwif->next) != hgif); }}static void do_ide0_request (void) /* invoked with cli() */{ do_hwgroup_request (ide_hwifs[0].hwgroup);}#if MAX_HWIFS > 1static void do_ide1_request (void) /* invoked with cli() */{ do_hwgroup_request (ide_hwifs[1].hwgroup);}#endif#if MAX_HWIFS > 2static void do_ide2_request (void) /* invoked with cli() */{ do_hwgroup_request (ide_hwifs[2].hwgroup);}#endif#if MAX_HWIFS > 3static void do_ide3_request (void) /* invoked with cli() */{ do_hwgroup_request (ide_hwifs[3].hwgroup);}#endifstatic void timer_expiry (unsigned long data){ ide_hwgroup_t *hwgroup = (ide_hwgroup_t *) data; ide_drive_t *drive = hwgroup->drive; unsigned long flags; save_flags(flags); cli(); if (hwgroup->poll_timeout != 0) { /* polling in progress? */ ide_handler_t *handler = hwgroup->handler; hwgroup->handler = NULL; handler(drive); } else if (hwgroup->handler == NULL) { /* not waiting for anything? */ sti(); /* drive must have responded just as the timer expired */ printk("%s: marginal timeout\n", drive->name); } else { hwgroup->handler = NULL; /* abort the operation */ if (hwgroup->hwif->dmaproc) (void) hwgroup->hwif->dmaproc (ide_dma_abort, drive); ide_error(drive, "irq timeout", GET_STAT()); } if (hwgroup->handler == NULL) do_hwgroup_request (hwgroup); restore_flags(flags);}/* * There's nothing really useful we can do with an unexpected interrupt, * other than reading the status register (to clear it), and logging it. * There should be no way that an irq can happen before we're ready for it, * so we needn't worry much about losing an "important" interrupt here. * * On laptops (and "green" PCs), an unexpected interrupt occurs whenever the * drive enters "idle", "standby", or "sleep" mode, so if the status looks * "good", we just ignore the interrupt completely. * * This routine assumes cli() is in effect when called. * * If an unexpected interrupt happens on irq15 while we are handling irq14 * and if the two interfaces are "serialized" (CMD640), then it looks like * we could screw up by interfering with a new request being set up for irq15. * * In reality, this is a non-issue. The new command is not sent unless the * drive is ready to accept one, in which case we know the drive is not * trying to interrupt us. And ide_set_handler() is always invoked before * completing the issuance of any new drive command, so we will not be * accidently invoked as a result of any valid command completion interrupt. * */static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup){ byte stat; unsigned int unit; ide_hwif_t *hwif = hwgroup->hwif; /* * handle the unexpected interrupt */ do { if (hwif->irq == irq) { for (unit = 0; unit < MAX_DRIVES; ++unit) { ide_drive_t *drive = &hwif->drives[unit]; if (!drive->present) continue; SELECT_DRIVE(hwif,drive); udelay(100); /* Ugly, but wait_stat() may not be safe here */ if (!OK_STAT(stat=GET_STAT(), drive->ready_stat, BAD_STAT)) { /* Try to not flood the console with msgs */ static unsigned long last_msgtime = 0; if ((last_msgtime + (HZ/2)) < jiffies) { last_msgtime = jiffies; (void) ide_dump_status(drive, "unexpected_intr", stat); } } if ((stat & DRQ_STAT)) try_to_flush_leftover_data(drive); } } } while ((hwif = hwif->next) != hwgroup->hwif); SELECT_DRIVE(hwif,hwgroup->drive); /* Ugh.. probably interrupts current I/O */ udelay(100); /* Ugly, but wait_stat() may not be safe here */}/* * entry point for all interrupts, caller does cli() for us */void ide_intr (int irq, void *dev_id, struct pt_regs *regs){ ide_hwgroup_t *hwgroup = dev_id; ide_handler_t *handler; if (irq == hwgroup->hwif->irq && (handler = hwgroup->handler) != NULL) { ide_drive_t *drive = hwgroup->drive; hwgroup->handler = NULL; del_timer(&(hwgroup->timer)); if (drive->unmask) sti(); handler(drive); cli(); /* this is necessary, as next rq may be different irq */ if (hwgroup->handler == NULL) { SET_RECOVERY_TIMER(HWIF(drive)); ide_do_request(hwgroup); } } else { unexpected_intr(irq, hwgroup); } cli();}/* * get_info_ptr() returns the (ide_drive_t *) for a given device number. * It returns NULL if the given device number does not match any present drives. */static ide_drive_t *get_info_ptr (kdev_t i_rdev){ int major = MAJOR(i_rdev); unsigned int h; for (h = 0; h < MAX_HWIFS; ++h) { ide_hwif_t *hwif = &ide_hwifs[h]; if (hwif->present && major == hwif->major) { unsigned unit = DEVICE_NR(i_rdev); if (unit < MAX_DRIVES) { ide_drive_t *drive = &hwif->drives[unit]; if (drive->present) return drive; } else if (major == IDE0_MAJOR && unit < 4) { printk("ide: probable bad entry for /dev/hd%c\n", 'a'+unit); printk("ide: to fix it, run: /usr/src/linux/scripts/MAKEDEV.ide\n"); } break; } } return NULL;}/* * This function is intended to be used prior to invoking ide_do_drive_cmd(). */void ide_init_drive_cmd (struct request *rq){ rq->buffer = NULL; rq->cmd = IDE_DRIVE_CMD; rq->sector = 0; rq->nr_sectors = 0; rq->current_nr_sectors = 0; rq->sem = NULL; rq->bh = NULL; rq->bhtail = NULL; rq->next = NULL;#if 0 /* these are done each time through ide_do_drive_cmd() */ rq->errors = 0; rq->rq_status = RQ_ACTIVE; rq->rq_dev = ????;#endif}/* * 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. (Currently used by ide-tape.c, * when operating in the pipelined operation mode). */int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t action){ unsigned long flags; unsigned int major = HWIF(drive)->major; struct request *cur_rq; struct blk_dev_struct *bdev = &blk_dev[major]; struct semaphore sem = MUTEX_LOCKED; if (IS_PROMISE_DRIVE && rq->buffer != NULL) return -ENOSYS; /* special drive cmds not supported */ 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; unplug_device(bdev); save_flags(flags); cli(); if (action == ide_next) HWGROUP(drive)->next_hwif = HWIF(drive); cur_rq = bdev->current_request; if (cur_rq == NULL || action == ide_preempt) { rq->next = cur_rq; bdev->current_request = rq; if (action == ide_preempt) HWGROUP(drive)->rq = NULL; } else { if (action == ide_wait || action == ide_end) { while (cur_rq->next != NULL) /* find end of list */ cur_rq = cur_rq->next; } rq->next = cur_rq->next; cur_rq->next = rq; } if (!HWGROUP(drive)->active) { do_hwgroup_request(HWGROUP(drive)); cli(); } if (action == ide_wait && rq->rq_status != RQ_INACTIVE) down(&sem); /* wait for it to be serviced */ restore_flags(flags); return rq->errors ? -EIO : 0; /* return -EIO if errors */}static int ide_open(struct inode * inode, struct file * filp){ ide_dr
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -