?? ide3.c
字號:
*/ for (unit = 0; unit < MAX_DRIVES; ++unit) pre_reset(&hwif->drives[unit]);#if OK_TO_RESET_CONTROLLER if (!IDE_CONTROL_REG) { __restore_flags(flags); return ide_stopped; } /* * 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 */ if (drive->quirk_list == 2) { OUT_BYTE(drive->ctl,IDE_CONTROL_REG); /* clear SRST and nIEN */ } else { 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, NULL); /* * Some weird controller like resetting themselves to a strange * state when the disks are reset this way. At least, the Winbond * 553 documentation says that */ if (hwif->resetproc != NULL) hwif->resetproc(drive);#endif /* OK_TO_RESET_CONTROLLER */ __restore_flags (flags); /* local CPU only */ return ide_started;}/* * ide_do_reset() is the entry point to the drive/interface reset code. */ide_startstop_t ide_do_reset (ide_drive_t *drive){ return do_reset1 (drive, 0);}static inline u32 read_24 (ide_drive_t *drive){ return (IN_BYTE(IDE_HCYL_REG)<<16) | (IN_BYTE(IDE_LCYL_REG)<<8) | IN_BYTE(IDE_SECTOR_REG);}/* * 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; 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: { 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); } break; } case IDE_DRIVE_TASK: { 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); args[3] = IN_BYTE(IDE_SECTOR_REG); args[4] = IN_BYTE(IDE_LCYL_REG); args[5] = IN_BYTE(IDE_HCYL_REG); args[6] = IN_BYTE(IDE_SELECT_REG); } break; } case IDE_DRIVE_TASKFILE: { ide_task_t *args = (ide_task_t *) rq->special; rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT); if (args) { if (args->tf_in_flags.b.data) { unsigned short data = IN_WORD(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] = IN_BYTE(IDE_NSECTOR_REG); args->tfRegister[IDE_SECTOR_OFFSET] = IN_BYTE(IDE_SECTOR_REG); args->tfRegister[IDE_LCYL_OFFSET] = IN_BYTE(IDE_LCYL_REG); args->tfRegister[IDE_HCYL_OFFSET] = IN_BYTE(IDE_HCYL_REG); args->tfRegister[IDE_SELECT_OFFSET] = IN_BYTE(IDE_SELECT_REG); args->tfRegister[IDE_STATUS_OFFSET] = stat; if ((drive->id->command_set_2 & 0x0400) && (drive->id->cfs_enable_2 & 0x0400) && (drive->addressing == 1)) { OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG_HOB); args->hobRegister[IDE_FEATURE_OFFSET_HOB] = IN_BYTE(IDE_FEATURE_REG); args->hobRegister[IDE_NSECTOR_OFFSET_HOB] = IN_BYTE(IDE_NSECTOR_REG); args->hobRegister[IDE_SECTOR_OFFSET_HOB] = IN_BYTE(IDE_SECTOR_REG); args->hobRegister[IDE_LCYL_OFFSET_HOB] = IN_BYTE(IDE_LCYL_REG); args->hobRegister[IDE_HCYL_OFFSET_HOB] = IN_BYTE(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);}/* * 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); /* local CPU only */ ide__sti(); /* local CPU only */ printk("%s: %s: status=0x%02x", drive->name, msg, stat);#if FANCY_STATUS_DUMPS 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 & ABRT_ERR) printk("DriveStatusError "); if (err & ICRC_ERR) printk("%s", (err & ABRT_ERR) ? "BadCRC " : "BadSector "); if (err & ECC_ERR) printk("UncorrectableError "); if (err & ID_ERR) printk("SectorIdNotFound "); if (err & TRK0_ERR) printk("TrackZeroNotFound "); if (err & MARK_ERR) printk("AddrMarkNotFound "); printk("}"); if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR || (err & (ECC_ERR|ID_ERR|MARK_ERR))) { if ((drive->id->command_set_2 & 0x0400) && (drive->id->cfs_enable_2 & 0x0400) && (drive->addressing == 1)) { __u64 sectors = 0; u32 low = 0, high = 0; low = read_24(drive); OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG); high = read_24(drive); sectors = ((__u64)high << 24) | low; printk(", LBAsect=%llu, high=%d, low=%d", (unsigned long long) sectors, high, low); } else { 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) && HWGROUP(drive)->rq) printk(", sector=%ld", HWGROUP(drive)->rq->sector); } }#endif /* FANCY_STATUS_DUMPS */ printk("\n"); } __restore_flags (flags); /* local CPU only */ 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; if (drive->media != ide_disk) return; while (i > 0) { u32 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 drive. */ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, byte stat){ struct request *rq; byte err; err = ide_dump_status(drive, msg, stat); if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL) return ide_stopped; /* 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 && (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 ide_stopped; /* some newer drives don't support WIN_SPECIFY */ } else if ((err & (ABRT_ERR | ICRC_ERR)) == (ABRT_ERR | ICRC_ERR)) { 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; } if ((stat & DRQ_STAT) && rq->cmd != WRITE) try_to_flush_leftover_data(drive); } if (GET_STAT() & (BUSY_STAT|DRQ_STAT)) OUT_BYTE(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG); /* force an abort */ if (rq->errors >= ERROR_MAX) { if (drive->driver != NULL) DRIVER(drive)->end_request(0, HWGROUP(drive)); else ide_end_request(0, HWGROUP(drive)); } 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;}/* * Issue a simple drive command * The drive must be selected beforehand. */void ide_cmd (ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler){ ide_set_handler (drive, handler, WAIT_CMD, NULL); if (IDE_CONTROL_REG) OUT_BYTE(drive->ctl,IDE_CONTROL_REG); /* clear nIEN */ SELECT_MASK(HWIF(drive),drive,0); OUT_BYTE(nsect,IDE_NSECTOR_REG); OUT_BYTE(cmd,IDE_COMMAND_REG);}/* * drive_cmd_intr() is invoked on completion of a special DRIVE_CMD. */static ide_startstop_t drive_cmd_intr (ide_drive_t *drive){ struct request *rq = HWGROUP(drive)->rq; byte *args = (byte *) rq->buffer; byte stat = GET_STAT(); int retries = 10; ide__sti(); /* local CPU only */ if ((stat & DRQ_STAT) && args && args[3]) { byte io_32bit = drive->io_32bit; drive->io_32bit = 0; ide_input_data(drive, &args[4], args[3] * SECTOR_WORDS); drive->io_32bit = io_32bit; while (((stat = GET_STAT()) & BUSY_STAT) && retries--) udelay(100); } if (!OK_STAT(stat, READY_STAT, BAD_STAT)) return ide_error(drive, "drive_cmd", stat); /* calls ide_end_drive_cmd */ ide_end_drive_cmd (drive, stat, GET_ERR()); return ide_stopped;}/* * 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. */static 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) { ide_tuneproc_t *tuneproc = HWIF(drive)->tuneproc; s->b.set_tune = 0; if (tuneproc != NULL) tuneproc(drive, drive->tune_req); } else if (drive->driver != NULL) { return DRIVER(drive)->special(drive); } else if (s->all) { printk("%s: bad special flag: 0x%02x\n", drive->name, s->all); s->all = 0; } return ide_stopped;}/* * This routine busy-waits for the drive status to be not "busy". * It then checks the status for all of the "good" bits and none * of the "bad" bits, and if all is okay it returns 0. All other * cases return 1 after invoking ide_error() -- caller should just return. * * This routine should get fixed to not hog the cpu during extra long waits.. * That could be done by busy-waiting for the first jiffy or two, and then * setting a timer to wake up at half second intervals thereafter, * until timeout is achieved, before timing out. */int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, byte good, byte bad, unsigned long timeout) { byte stat; int i; unsigned long flags; /* bail early if we've exceeded max_failures */ if (drive->max_failures && (drive->failures > drive->max_failures)) { *startstop = ide_stopped; return 1; } udelay(1); /* spec allows drive 400ns to assert "BUSY" */ if ((stat = GET_STAT()) & BUSY_STAT) { __save_flags(flags); /* local CPU only */ ide__sti(); /* local CPU only */ timeout += jiffies; while ((stat = GET_STAT()) & BUSY_STAT) { if (0 < (signed long)(jiffies - timeout)) { __restore_flags(flags); /* local CPU only */ *startstop = ide_error(drive, "status timeout", stat); return 1; } } __restore_flags(flags); /* local CPU only */ } /* * Allow status to settle, then read it again. * A few rare drives vastly violate the 400ns spec here, * so we'll wait up to 10usec for a "good" status * rather than expensively fail things immediately. * This fix courtesy of Matthew Faupel & Niccolo Rigacci. */ for (i = 0; i < 10; i++) { udelay(1); if (OK_STAT((stat = GET_STAT()), good, bad))
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -