📄 ide.c
字号:
break; case 2: printk("formatter device error"); break; case 3: printk("sector buffer error"); break; case 4: printk("ECC circuitry error"); break; case 5: printk("controlling MPU error"); break; default:printk("error (0x%02x?)", tmp); } if (tmp & 0x80) printk("; slave: failed"); printk("\n");#else printk("failed\n");#endif /* FANCY_STATUS_DUMPS */ } } hwgroup->poll_timeout = 0; /* done polling */}/* * do_reset1() attempts to recover a confused drive by resetting it. * Unfortunately, resetting a disk drive actually resets all devices on * the same interface, so it can really be thought of as resetting the * interface rather than resetting the drive. * * ATAPI devices have their own reset mechanism which allows them to be * individually reset without clobbering other devices on the same interface. * * Unfortunately, the IDE interface does not generate an interrupt to let * us know when the reset operation has finished, so we must poll for this. * Equally poor, though, is the fact that this may a very long time to complete, * (up to 30 seconds worstcase). So, instead of busy-waiting here for it, * we set a timer to poll at 50ms intervals. */static void do_reset1 (ide_drive_t *drive, int do_not_try_atapi){ unsigned int unit; unsigned long flags; ide_hwif_t *hwif = HWIF(drive); ide_hwgroup_t *hwgroup = HWGROUP(drive); save_flags(flags); cli(); /* Why ? */#ifdef CONFIG_BLK_DEV_IDEATAPI /* For an ATAPI device, first try an ATAPI SRST. */ if (drive->media != ide_disk) { if (!do_not_try_atapi) { if (!drive->keep_settings) { drive->unmask = 0; drive->io_32bit = 0; } OUT_BYTE (drive->select.all, IDE_SELECT_REG); udelay (20); OUT_BYTE (WIN_SRST, IDE_COMMAND_REG); hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20); restore_flags (flags); return; } }#endif /* CONFIG_BLK_DEV_IDEATAPI */ /* * First, reset any device state data we were maintaining * for any of the drives on this interface. */ for (unit = 0; unit < MAX_DRIVES; ++unit) { ide_drive_t *rdrive = &hwif->drives[unit];#ifdef CONFIG_BLK_DEV_IDETAPE if (rdrive->media == ide_tape) rdrive->tape.reset_issued = 1;#endif /* CONFIG_BLK_DEV_IDETAPE */ rdrive->special.all = 0; rdrive->special.b.set_geometry = 1; rdrive->special.b.recalibrate = 1; if (OK_TO_RESET_CONTROLLER) rdrive->mult_count = 0; if (!rdrive->keep_settings) { rdrive->mult_req = 0; rdrive->unmask = 0; rdrive->io_32bit = 0; if (rdrive->using_dma) { rdrive->using_dma = 0; printk("%s: disabled DMA\n", rdrive->name); } } if (rdrive->mult_req != rdrive->mult_count) rdrive->special.b.set_multmode = 1; }#if OK_TO_RESET_CONTROLLER /* * Note that we also set nIEN while resetting the device, * to mask unwanted interrupts from the interface during the reset. * However, due to the design of PC hardware, this will cause an * immediate interrupt due to the edge transition it produces. * This single interrupt gives us a "fast poll" for drives that * recover from reset very quickly, saving us the first 50ms wait time. */ OUT_BYTE(drive->ctl|6,IDE_CONTROL_REG); /* set SRST and nIEN */ udelay(10); /* more than enough time */ OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG); /* clear SRST, leave nIEN */ udelay(10); /* more than enough time */ hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; ide_set_handler (drive, &reset_pollfunc, HZ/20);#endif /* OK_TO_RESET_CONTROLLER */ restore_flags (flags);}/* * ide_do_reset() is the entry point to the drive/interface reset code. */void ide_do_reset (ide_drive_t *drive){ do_reset1 (drive, 0);#ifdef CONFIG_BLK_DEV_IDETAPE if (drive->media == ide_tape) drive->tape.reset_issued=1;#endif /* CONFIG_BLK_DEV_IDETAPE */}/* * Clean up after success/failure of an explicit drive cmd */void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err){ unsigned long flags; struct request *rq = HWGROUP(drive)->rq; if (rq->cmd == IDE_DRIVE_CMD) { byte *args = (byte *) rq->buffer; rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT); if (args) { args[0] = stat; args[1] = err; args[2] = IN_BYTE(IDE_NSECTOR_REG); } } save_flags(flags); cli(); blk_dev[MAJOR(rq->rq_dev)].current_request = rq->next; HWGROUP(drive)->rq = NULL; rq->rq_status = RQ_INACTIVE; if (rq->sem != NULL) up(rq->sem); restore_flags(flags);}/* * Error reporting, in human readable form (luxurious, but a memory hog). */byte ide_dump_status (ide_drive_t *drive, const char *msg, byte stat){ unsigned long flags; byte err = 0; save_flags (flags); sti(); printk("%s: %s: status=0x%02x", drive->name, msg, stat);#if FANCY_STATUS_DUMPS if (drive->media == ide_disk) { printk(" { "); if (stat & BUSY_STAT) printk("Busy "); else { if (stat & READY_STAT) printk("DriveReady "); if (stat & WRERR_STAT) printk("DeviceFault "); if (stat & SEEK_STAT) printk("SeekComplete "); if (stat & DRQ_STAT) printk("DataRequest "); if (stat & ECC_STAT) printk("CorrectedError "); if (stat & INDEX_STAT) printk("Index "); if (stat & ERR_STAT) printk("Error "); } printk("}"); }#endif /* FANCY_STATUS_DUMPS */ printk("\n"); if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) { err = GET_ERR(); printk("%s: %s: error=0x%02x", drive->name, msg, err);#if FANCY_STATUS_DUMPS if (drive->media == ide_disk) { printk(" { "); if (err & ICRC_ERR) printk((err & ABRT_ERR) ? "BadCRC " : "BadSector "); if (err & ECC_ERR) printk("UncorrectableError "); if (err & ID_ERR) printk("SectorIdNotFound "); if (err & ABRT_ERR) printk("DriveStatusError "); if (err & TRK0_ERR) printk("TrackZeroNotFound "); if (err & MARK_ERR) printk("AddrMarkNotFound "); printk("}"); if (err & (BBD_ERR|ECC_ERR|ID_ERR|MARK_ERR)) { byte cur = IN_BYTE(IDE_SELECT_REG); if (cur & 0x40) { /* using LBA? */ printk(", LBAsect=%ld", (unsigned long) ((cur&0xf)<<24) |(IN_BYTE(IDE_HCYL_REG)<<16) |(IN_BYTE(IDE_LCYL_REG)<<8) | IN_BYTE(IDE_SECTOR_REG)); } else { printk(", CHS=%d/%d/%d", (IN_BYTE(IDE_HCYL_REG)<<8) + IN_BYTE(IDE_LCYL_REG), cur & 0xf, IN_BYTE(IDE_SECTOR_REG)); } if (HWGROUP(drive)->rq) printk(", sector=%ld", HWGROUP(drive)->rq->sector); } }#endif /* FANCY_STATUS_DUMPS */ printk("\n"); } restore_flags (flags); return err;}/* * 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*. */static void try_to_flush_leftover_data (ide_drive_t *drive){ int i = (drive->mult_count ? drive->mult_count : 1) * SECTOR_WORDS; while (i > 0) { unsigned long buffer[16]; unsigned int wcount = (i > 16) ? 16 : i; i -= wcount; ide_input_data (drive, buffer, wcount); }}/* * ide_error() takes action based on the error returned by the controller. */void ide_error (ide_drive_t *drive, const char *msg, byte stat){ struct request *rq; byte err; err = ide_dump_status(drive, msg, stat); if ((rq = HWGROUP(drive)->rq) == NULL || drive == NULL) return; /* retry only "normal" I/O: */ if (rq->cmd == IDE_DRIVE_CMD) { rq->errors = 1; ide_end_drive_cmd(drive, stat, err); return; } if (stat & BUSY_STAT) { /* other bits are useless when BUSY */ rq->errors |= ERROR_RESET; } else { if (drive->media == ide_disk && (stat & ERR_STAT)) { /* err has different meaning on cdrom and tape */ if (err == ABRT_ERR) { if (drive->select.b.lba && IN_BYTE(IDE_COMMAND_REG) == WIN_SPECIFY) return; /* some newer drives don't support WIN_SPECIFY */ } else if ((err & (ABRT_ERR | ICRC_ERR)) == (ABRT_ERR | ICRC_ERR)) ; /* 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; else if (err & MC_ERR) drive->special.b.mc = 1; } if ((stat & DRQ_STAT) && rq->cmd != WRITE) try_to_flush_leftover_data(drive); } if (GET_STAT() & (BUSY_STAT|DRQ_STAT)) rq->errors |= ERROR_RESET; /* Mmmm.. timing problem */ if (rq->errors >= ERROR_MAX) {#ifdef CONFIG_BLK_DEV_IDETAPE if (drive->media == ide_tape) { rq->errors = 0; idetape_end_request(0, HWGROUP(drive)); } else#endif /* CONFIG_BLK_DEV_IDETAPE */#ifdef CONFIG_BLK_DEV_IDEFLOPPY if (drive->media == ide_floppy) { rq->errors = 0; idefloppy_end_request(0, HWGROUP(drive)); } else#endif /* CONFIG_BLK_DEV_IDEFLOPPY */#ifdef CONFIG_BLK_DEV_IDESCSI if (drive->media == ide_scsi) { rq->errors = 0; idescsi_end_request(0, HWGROUP(drive)); } else#endif /* CONFIG_BLK_DEV_IDESCSI */ ide_end_request(0, HWGROUP(drive)); } else { if ((rq->errors & ERROR_RESET) == ERROR_RESET) { ++rq->errors; ide_do_reset(drive); return; } else if ((rq->errors & ERROR_RECAL) == ERROR_RECAL) drive->special.b.recalibrate = 1; ++rq->errors; }}/* * read_intr() is the handler for disk read/multread interrupts */static void read_intr (ide_drive_t *drive){ byte stat; int i; unsigned int msect, nsect; struct request *rq; if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) { ide_error(drive, "read_intr", stat); return; } msect = drive->mult_count;read_next: rq = HWGROUP(drive)->rq; if (msect) { if ((nsect = rq->current_nr_sectors) > msect) nsect = msect; msect -= nsect; } else nsect = 1; ide_input_data(drive, rq->buffer, nsect * SECTOR_WORDS);#ifdef DEBUG printk("%s: read: sectors(%ld-%ld), buffer=0x%08lx, remaining=%ld\n", drive->name, rq->sector, rq->sector+nsect-1, (unsigned long) rq->buffer+(nsect<<9), rq->nr_sectors-nsect);#endif rq->sector += nsect; rq->buffer += nsect<<9; rq->errors = 0; i = (rq->nr_sectors -= nsect); if ((rq->current_nr_sectors -= nsect) <= 0) ide_end_request(1, HWGROUP(drive)); if (i > 0) { if (msect) goto read_next; ide_set_handler (drive, &read_intr, WAIT_CMD); }}/* * write_intr() is the handler for disk write interrupts */static void write_intr (ide_drive_t *drive){ byte stat; int i; ide_hwgroup_t *hwgroup = HWGROUP(drive); struct request *rq = hwgroup->rq; if (OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) {#ifdef DEBUG printk("%s: write: sector %ld, buffer=0x%08lx, remaining=%ld\n", drive->name, rq->sector, (unsigned long) rq->buffer, rq->nr_sectors-1);#endif if ((rq->nr_sectors == 1) ^ ((stat & DRQ_STAT) != 0)) { rq->sector++; rq->buffer += 512; rq->errors = 0; i = --rq->nr_sectors; --rq->current_nr_sectors; if (rq->current_nr_sectors <= 0) ide_end_request(1, hwgroup); if (i > 0) { ide_output_data (drive, rq->buffer, SECTOR_WORDS); ide_set_handler (drive, &write_intr, WAIT_CMD); } return; } } ide_error(drive, "write_intr", stat);}/* * ide_multwrite() transfers a block of up to mcount sectors of data * to a drive as part of a disk multiple-sector write operation. */void ide_multwrite (ide_drive_t *drive, unsigned int mcount){ struct request *rq = &HWGROUP(drive)->wrq; do { unsigned int nsect = rq->current_nr_sectors;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -