ide-io.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,604 行 · 第 1/4 页
C
1,604 行
args->hobRegister[IDE_HCYL_OFFSET] = hwif->INB(IDE_HCYL_REG); } } } else if (blk_pm_request(rq)) {#ifdef DEBUG_PM printk("%s: complete_power_step(step: %d, stat: %x, err: %x)\n", drive->name, rq->pm->pm_step, stat, err);#endif DRIVER(drive)->complete_power_step(drive, rq, stat, err); if (rq->pm->pm_step == ide_pm_state_completed) ide_complete_pm_request(drive, rq); return; } spin_lock_irqsave(&ide_lock, flags); blkdev_dequeue_request(rq); if (blk_barrier_preflush(rq) || blk_barrier_postflush(rq)) ide_complete_barrier(drive, rq, err); HWGROUP(drive)->rq = NULL; end_that_request_last(rq); spin_unlock_irqrestore(&ide_lock, flags);}EXPORT_SYMBOL(ide_end_drive_cmd);/** * try_to_flush_leftover_data - flush junk * @drive: drive to flush * * try_to_flush_leftover_data() is invoked in response to a drive * unexpectedly having its DRQ_STAT bit set. As an alternative to * resetting the drive, this routine tries to clear the condition * by read a sector's worth of data from the drive. Of course, * this may not help if the drive is *waiting* for data from *us*. */void try_to_flush_leftover_data (ide_drive_t *drive){ int i = (drive->mult_count ? drive->mult_count : 1) * SECTOR_WORDS; if (drive->media != ide_disk) return; while (i > 0) { u32 buffer[16]; u32 wcount = (i > 16) ? 16 : i; i -= wcount; HWIF(drive)->ata_input_data(drive, buffer, wcount); }}EXPORT_SYMBOL(try_to_flush_leftover_data);/* * FIXME Add an ATAPI error *//** * ide_error - handle an error on the IDE * @drive: drive the error occurred on * @msg: message to report * @stat: status bits * * ide_error() takes action based on the error returned by the drive. * For normal I/O that may well include retries. We deal with * both new-style (taskfile) and old style command handling here. * In the case of taskfile command handling there is work left to * do */ ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, u8 stat){ ide_hwif_t *hwif; struct request *rq; u8 err; err = ide_dump_status(drive, msg, stat); if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL) return ide_stopped; hwif = HWIF(drive); /* retry only "normal" I/O: */ if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK)) { rq->errors = 1; ide_end_drive_cmd(drive, stat, err); return ide_stopped; } if (rq->flags & REQ_DRIVE_TASKFILE) { rq->errors = 1; ide_end_drive_cmd(drive, stat, err); return ide_stopped; } if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) { /* other bits are useless when BUSY */ rq->errors |= ERROR_RESET; } else { if (drive->media != ide_disk) goto media_out; if (stat & ERR_STAT) { /* err has different meaning on cdrom and tape */ if (err == ABRT_ERR) { if (drive->select.b.lba && (hwif->INB(IDE_COMMAND_REG) == WIN_SPECIFY)) /* some newer drives don't * support WIN_SPECIFY */ return ide_stopped; } else if ((err & BAD_CRC) == BAD_CRC) { drive->crc_count++; /* UDMA crc error -- just retry the operation */ } else if (err & (BBD_ERR | ECC_ERR)) { /* retries won't help these */ rq->errors = ERROR_MAX; } else if (err & TRK0_ERR) { /* help it find track zero */ rq->errors |= ERROR_RECAL; } }media_out: if ((stat & DRQ_STAT) && rq_data_dir(rq) != WRITE) try_to_flush_leftover_data(drive); } if (hwif->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT)) { /* force an abort */ hwif->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG); } if (rq->errors >= ERROR_MAX) { DRIVER(drive)->end_request(drive, 0, 0); } else { if ((rq->errors & ERROR_RESET) == ERROR_RESET) { ++rq->errors; return ide_do_reset(drive); } if ((rq->errors & ERROR_RECAL) == ERROR_RECAL) drive->special.b.recalibrate = 1; ++rq->errors; } return ide_stopped;}EXPORT_SYMBOL(ide_error);/** * ide_abort - abort pending IDE operatins * @drive: drive the error occurred on * @msg: message to report * * ide_abort kills and cleans up when we are about to do a * host initiated reset on active commands. Longer term we * want handlers to have sensible abort handling themselves * * This differs fundamentally from ide_error because in * this case the command is doing just fine when we * blow it away. */ ide_startstop_t ide_abort(ide_drive_t *drive, const char *msg){ ide_hwif_t *hwif; struct request *rq; if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL) return ide_stopped; hwif = HWIF(drive); /* retry only "normal" I/O: */ if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK)) { rq->errors = 1; ide_end_drive_cmd(drive, BUSY_STAT, 0); return ide_stopped; } if (rq->flags & REQ_DRIVE_TASKFILE) { rq->errors = 1; ide_end_drive_cmd(drive, BUSY_STAT, 0); return ide_stopped; } rq->errors |= ERROR_RESET; DRIVER(drive)->end_request(drive, 0, 0); return ide_stopped;}EXPORT_SYMBOL(ide_abort);/** * ide_cmd - issue a simple drive command * @drive: drive the command is for * @cmd: command byte * @nsect: sector byte * @handler: handler for the command completion * * Issue a simple drive command with interrupts. * The drive must be selected beforehand. */void ide_cmd (ide_drive_t *drive, u8 cmd, u8 nsect, ide_handler_t *handler){ ide_hwif_t *hwif = HWIF(drive); if (IDE_CONTROL_REG) hwif->OUTB(drive->ctl,IDE_CONTROL_REG); /* clear nIEN */ SELECT_MASK(drive,0); hwif->OUTB(nsect,IDE_NSECTOR_REG); ide_execute_command(drive, cmd, handler, WAIT_CMD, NULL);}EXPORT_SYMBOL(ide_cmd);/** * drive_cmd_intr - drive command completion interrupt * @drive: drive the completion interrupt occurred on * * drive_cmd_intr() is invoked on completion of a special DRIVE_CMD. * We do any necessary daya reading and then wait for the drive to * go non busy. At that point we may read the error data and complete * the request */ ide_startstop_t drive_cmd_intr (ide_drive_t *drive){ struct request *rq = HWGROUP(drive)->rq; ide_hwif_t *hwif = HWIF(drive); u8 *args = (u8 *) rq->buffer; u8 stat = hwif->INB(IDE_STATUS_REG); int retries = 10; local_irq_enable(); if ((stat & DRQ_STAT) && args && args[3]) { u8 io_32bit = drive->io_32bit; drive->io_32bit = 0; hwif->ata_input_data(drive, &args[4], args[3] * SECTOR_WORDS); drive->io_32bit = io_32bit; while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--) udelay(100); } if (!OK_STAT(stat, READY_STAT, BAD_STAT) && DRIVER(drive) != NULL) return DRIVER(drive)->error(drive, "drive_cmd", stat); /* calls ide_end_drive_cmd */ ide_end_drive_cmd(drive, stat, hwif->INB(IDE_ERROR_REG)); return ide_stopped;}EXPORT_SYMBOL(drive_cmd_intr);/** * do_special - issue some special commands * @drive: drive the command is for * * do_special() is used to issue WIN_SPECIFY, WIN_RESTORE, and WIN_SETMULT * commands to a drive. It used to do much more, but has been scaled * back. */ide_startstop_t do_special (ide_drive_t *drive){ special_t *s = &drive->special;#ifdef DEBUG printk("%s: do_special: 0x%02x\n", drive->name, s->all);#endif if (s->b.set_tune) { s->b.set_tune = 0; if (HWIF(drive)->tuneproc != NULL) HWIF(drive)->tuneproc(drive, drive->tune_req); return ide_stopped; } else return DRIVER(drive)->special(drive);}EXPORT_SYMBOL(do_special);/** * execute_drive_command - issue special drive command * @drive: the drive to issue th command on * @rq: the request structure holding the command * * execute_drive_cmd() issues a special drive command, usually * initiated by ioctl() from the external hdparm program. The * command can be a drive command, drive task or taskfile * operation. Weirdly you can call it with NULL to wait for * all commands to finish. Don't do this as that is due to change */ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq){ ide_hwif_t *hwif = HWIF(drive); if (rq->flags & REQ_DRIVE_TASKFILE) { ide_task_t *args = rq->special; if (!args) goto done; hwif->data_phase = args->data_phase; if (args->tf_out_flags.all != 0) return flagged_taskfile(drive, args); return do_rw_taskfile(drive, args); } else if (rq->flags & REQ_DRIVE_TASK) { u8 *args = rq->buffer; u8 sel; if (!args) goto done;#ifdef DEBUG printk("%s: DRIVE_TASK_CMD ", drive->name); printk("cmd=0x%02x ", args[0]); printk("fr=0x%02x ", args[1]); printk("ns=0x%02x ", args[2]); printk("sc=0x%02x ", args[3]); printk("lcyl=0x%02x ", args[4]); printk("hcyl=0x%02x ", args[5]); printk("sel=0x%02x\n", args[6]);#endif hwif->OUTB(args[1], IDE_FEATURE_REG); hwif->OUTB(args[3], IDE_SECTOR_REG); hwif->OUTB(args[4], IDE_LCYL_REG); hwif->OUTB(args[5], IDE_HCYL_REG); sel = (args[6] & ~0x10); if (drive->select.b.unit) sel |= 0x10; hwif->OUTB(sel, IDE_SELECT_REG); ide_cmd(drive, args[0], args[2], &drive_cmd_intr); return ide_started; } else if (rq->flags & REQ_DRIVE_CMD) { u8 *args = rq->buffer; if (!args) goto done;#ifdef DEBUG printk("%s: DRIVE_CMD ", drive->name); printk("cmd=0x%02x ", args[0]); printk("sc=0x%02x ", args[1]); printk("fr=0x%02x ", args[2]); printk("xx=0x%02x\n", args[3]);#endif if (args[0] == WIN_SMART) { hwif->OUTB(0x4f, IDE_LCYL_REG); hwif->OUTB(0xc2, IDE_HCYL_REG); hwif->OUTB(args[2],IDE_FEATURE_REG); hwif->OUTB(args[1],IDE_SECTOR_REG); ide_cmd(drive, args[0], args[3], &drive_cmd_intr); return ide_started; } hwif->OUTB(args[2],IDE_FEATURE_REG); ide_cmd(drive, args[0], args[1], &drive_cmd_intr); return ide_started; }done: /* * NULL is actually a valid way of waiting for * all current requests to be flushed from the queue. */#ifdef DEBUG printk("%s: DRIVE_CMD (null)\n", drive->name);#endif ide_end_drive_cmd(drive, hwif->INB(IDE_STATUS_REG), hwif->INB(IDE_ERROR_REG)); return ide_stopped;}EXPORT_SYMBOL(execute_drive_cmd);/** * start_request - start of I/O and command issuing for IDE * * start_request() initiates handling of a new I/O request. It * accepts commands and I/O (read/write) requests. It also does * the final remapping for weird stuff like EZDrive. Once * device mapper can work sector level the EZDrive stuff can go away * * FIXME: this function needs a rename */ ide_startstop_t start_request (ide_drive_t *drive, struct request *rq){ ide_startstop_t startstop; sector_t block; BUG_ON(!(rq->flags & REQ_STARTED));#ifdef DEBUG printk("%s: start_request: current=0x%08lx\n", HWIF(drive)->name, (unsigned long) rq);#endif /* bail early if we've exceeded max_failures */ if (drive->max_failures && (drive->failures > drive->max_failures)) { goto kill_rq; } /* * bail early if we've sent a device to sleep, however how to wake * this needs to be a masked flag. FIXME for proper operations. */ if (drive->suspend_reset)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?