?? ide-io.c
字號:
/* * IDE I/O functions * * Basic PIO and command management functionality. * * This code was split off from ide.c. See ide.c for history and original * copyrights. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * For the avoidance of doubt the "preferred form" of this code is one which * is in an open non patent encumbered format. Where cryptographic key signing * forms part of the process of creating an executable the information * including keys needed to generate an equivalently functional executable * are deemed to be part of the source code. */ #include <linux/config.h>#include <linux/module.h>#include <linux/types.h>#include <linux/string.h>#include <linux/kernel.h>#include <linux/timer.h>#include <linux/mm.h>#include <linux/interrupt.h>#include <linux/major.h>#include <linux/errno.h>#include <linux/genhd.h>#include <linux/blkpg.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/pci.h>#include <linux/delay.h>#include <linux/ide.h>#include <linux/devfs_fs_kernel.h>#include <linux/completion.h>#include <linux/reboot.h>#include <linux/cdrom.h>#include <linux/seq_file.h>#include <linux/kmod.h>#include <asm/byteorder.h>#include <asm/irq.h>#include <asm/uaccess.h>#include <asm/io.h>#include <asm/bitops.h>#include "ide_modes.h"#if (DISK_RECOVERY_TIME > 0)Error So the User Has To Fix the Compilation And Stop Hacking Port 0x43Does anyone ever use this anyway ??/* * For really screwy hardware (hey, at least it *can* be used with Linux) * we can enforce a minimum delay time between successive operations. */static unsigned long read_timer (ide_hwif_t *hwif){ unsigned long t, flags; int i; /* FIXME this is completely unsafe! */ local_irq_save(flags); t = jiffies * 11932; outb_p(0, 0x43); i = inb_p(0x40); i |= inb_p(0x40) << 8; local_irq_restore(flags); return (t - i);}#endif /* DISK_RECOVERY_TIME */static inline void set_recovery_timer (ide_hwif_t *hwif){#if (DISK_RECOVERY_TIME > 0) hwif->last_time = read_timer(hwif);#endif /* DISK_RECOVERY_TIME */}/* * ide_end_request - complete an IDE I/O * @drive: IDE device for the I/O * @uptodate: * * This is our end_request wrapper function. We complete the I/O * update random number input and dequeue the request. */ int ide_end_request (ide_drive_t *drive, int uptodate){ struct request *rq; unsigned long flags; int ret = 1; spin_lock_irqsave(&io_request_lock, flags); rq = HWGROUP(drive)->rq; /* * decide whether to reenable DMA -- 3 is a random magic for now, * if we DMA timeout more than 3 times, just stay in PIO */ if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) { drive->state = 0; HWGROUP(drive)->hwif->ide_dma_on(drive); } if (!end_that_request_first(rq, uptodate, drive->name)) { add_blkdev_randomness(MAJOR(rq->rq_dev)); blkdev_dequeue_request(rq); HWGROUP(drive)->rq = NULL; end_that_request_last(rq); ret = 0; } spin_unlock_irqrestore(&io_request_lock, flags); return ret;}EXPORT_SYMBOL(ide_end_request);/** * ide_end_drive_cmd - end an explicit drive command * @drive: command * @stat: status bits * @err: error bits * * Clean up after success/failure of an explicit drive command. * These get thrown onto the queue so they are synchronized with * real I/O operations on the drive. * * In LBA48 mode we have to read the register set twice to get * all the extra information out. */ void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err){ ide_hwif_t *hwif = HWIF(drive); unsigned long flags; struct request *rq; spin_lock_irqsave(&io_request_lock, flags); rq = HWGROUP(drive)->rq; spin_unlock_irqrestore(&io_request_lock, flags); switch(rq->cmd) { case IDE_DRIVE_CMD: { u8 *args = (u8 *) rq->buffer; if (rq->errors == 0) rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT); if (args) { args[0] = stat; args[1] = err; args[2] = hwif->INB(IDE_NSECTOR_REG); } break; } case IDE_DRIVE_TASK: { u8 *args = (u8 *) rq->buffer; if (rq->errors == 0) rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT); if (args) { args[0] = stat; args[1] = err; args[2] = hwif->INB(IDE_NSECTOR_REG); args[3] = hwif->INB(IDE_SECTOR_REG); args[4] = hwif->INB(IDE_LCYL_REG); args[5] = hwif->INB(IDE_HCYL_REG); args[6] = hwif->INB(IDE_SELECT_REG); } break; } case IDE_DRIVE_TASKFILE: { ide_task_t *args = (ide_task_t *) rq->special; if (rq->errors == 0) rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT); if (args) { if (args->tf_in_flags.b.data) { u16 data = hwif->INW(IDE_DATA_REG); args->tfRegister[IDE_DATA_OFFSET] = (data) & 0xFF; args->hobRegister[IDE_DATA_OFFSET_HOB] = (data >> 8) & 0xFF; } args->tfRegister[IDE_ERROR_OFFSET] = err; args->tfRegister[IDE_NSECTOR_OFFSET] = hwif->INB(IDE_NSECTOR_REG); args->tfRegister[IDE_SECTOR_OFFSET] = hwif->INB(IDE_SECTOR_REG); args->tfRegister[IDE_LCYL_OFFSET] = hwif->INB(IDE_LCYL_REG); args->tfRegister[IDE_HCYL_OFFSET] = hwif->INB(IDE_HCYL_REG); args->tfRegister[IDE_SELECT_OFFSET] = hwif->INB(IDE_SELECT_REG); args->tfRegister[IDE_STATUS_OFFSET] = stat; if (drive->addressing == 1) { hwif->OUTB(drive->ctl|0x80, IDE_CONTROL_REG_HOB); args->hobRegister[IDE_FEATURE_OFFSET_HOB] = hwif->INB(IDE_FEATURE_REG); args->hobRegister[IDE_NSECTOR_OFFSET_HOB] = hwif->INB(IDE_NSECTOR_REG); args->hobRegister[IDE_SECTOR_OFFSET_HOB] = hwif->INB(IDE_SECTOR_REG); args->hobRegister[IDE_LCYL_OFFSET_HOB] = hwif->INB(IDE_LCYL_REG); args->hobRegister[IDE_HCYL_OFFSET_HOB] = hwif->INB(IDE_HCYL_REG); } } break; } default: break; } spin_lock_irqsave(&io_request_lock, flags); blkdev_dequeue_request(rq); HWGROUP(drive)->rq = NULL; end_that_request_last(rq); spin_unlock_irqrestore(&io_request_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->cmd == IDE_DRIVE_CMD || rq->cmd == IDE_DRIVE_TASK) { rq->errors = 1; ide_end_drive_cmd(drive, stat, err); return ide_stopped; } if (rq->cmd == IDE_DRIVE_TASKFILE) { rq->errors = 1; ide_end_drive_cmd(drive, stat, err);// ide_end_taskfile(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->cmd != 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); } 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->cmd == IDE_DRIVE_CMD || rq->cmd == IDE_DRIVE_TASK) { rq->errors = 1; ide_end_drive_cmd(drive, BUSY_STAT, 0); return ide_stopped; } if (rq->cmd == IDE_DRIVE_TASKFILE) { rq->errors = 1; ide_end_drive_cmd(drive, BUSY_STAT, 0);// ide_end_taskfile(drive, BUSY_STAT, 0); return ide_stopped; } rq->errors |= ERROR_RESET; DRIVER(drive)->end_request(drive, 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 neccessary 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)) 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
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -