📄 ide.c
字号:
unsigned long block, blockend; ide_drive_t *drive; sti();#ifdef DEBUG printk("%s: do_request: current=0x%08lx\n", hwif->name, (unsigned long) rq);#endif minor = MINOR(rq->rq_dev); unit = minor >> PARTN_BITS; if (MAJOR(rq->rq_dev) != hwif->major || unit >= MAX_DRIVES) { printk("%s: bad device number: %s\n", hwif->name, kdevname(rq->rq_dev)); goto kill_rq; } drive = &hwif->drives[unit];#ifdef DEBUG if (rq->bh && !buffer_locked(rq->bh)) { printk("%s: block not locked\n", drive->name); goto kill_rq; }#endif block = rq->sector; blockend = block + rq->nr_sectors; if ((blockend < block) || (blockend > drive->part[minor&PARTN_MASK].nr_sects)) { printk("%s%c: bad access: block=%ld, count=%ld\n", drive->name, (minor&PARTN_MASK)?'0'+(minor&PARTN_MASK):' ', block, rq->nr_sectors); goto kill_rq; } block += drive->part[minor&PARTN_MASK].start_sect + drive->sect0;#if FAKE_FDISK_FOR_EZDRIVE if (block == 0 && drive->remap_0_to_1) block = 1; /* redirect MBR access to EZ-Drive partn table */#endif /* FAKE_FDISK_FOR_EZDRIVE */ ((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->io.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 then 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -