⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ide.c

📁 基于组件方式开发操作系统的OSKIT源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	udelay(1);	/* need to guarantee 400ns since last command was issued */#endif	if (GET_STAT() & BUSY_STAT)		return 0;	/* drive busy:  definitely not interrupting */	return 1;		/* drive ready: *might* be interrupting */}/* * This is our end_request replacement function. */void ide_end_request(byte uptodate, ide_hwgroup_t *hwgroup){	struct request *rq;	unsigned long flags;	spin_lock_irqsave(&io_request_lock, flags);	rq = hwgroup->rq;	if (!end_that_request_first(rq, uptodate, hwgroup->drive->name)) {		add_blkdev_randomness(MAJOR(rq->rq_dev));		hwgroup->drive->queue = rq->next;        	blk_dev[MAJOR(rq->rq_dev)].current_request = NULL;        	hwgroup->rq = NULL;		end_that_request_last(rq);	}	spin_unlock_irqrestore(&io_request_lock, flags);}/* * This should get invoked any time we exit the driver to * wait for an interrupt response from a drive.  handler() points * at the appropriate code to handle the next interrupt, and a * timer is started to prevent us from waiting forever in case * something goes wrong (see the ide_timer_expiry() handler later on). */void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned int timeout){	unsigned long flags;	ide_hwgroup_t *hwgroup = HWGROUP(drive);	spin_lock_irqsave(&hwgroup->spinlock, flags);#ifdef DEBUG	if (hwgroup->handler != NULL) {		printk("%s: ide_set_handler: handler not null; old=%p, new=%p\n",			drive->name, hwgroup->handler, handler);	}#endif	hwgroup->handler       = handler;	hwgroup->timer.expires = jiffies + timeout;	add_timer(&(hwgroup->timer));	spin_unlock_irqrestore(&hwgroup->spinlock, flags);}/* * current_capacity() returns the capacity (in sectors) of a drive * according to its current geometry/LBA settings. */static unsigned long current_capacity (ide_drive_t *drive){	if (!drive->present)		return 0;	if (drive->driver != NULL)		return DRIVER(drive)->capacity(drive);	return 0;}/* * ide_geninit() is called exactly *once* for each major, from genhd.c, * at the beginning of the initial partition check for the drives. */void ide_geninit (struct gendisk *gd){	unsigned int unit;	ide_hwif_t *hwif = gd->real_devices;	for (unit = 0; unit < gd->nr_real; ++unit) {		ide_drive_t *drive = &hwif->drives[unit];		drive->part[0].nr_sects = current_capacity(drive);		if (!drive->present || (drive->media != ide_disk && drive->media != ide_floppy) ||		    drive->driver == NULL || !drive->part[0].nr_sects)			drive->part[0].start_sect = -1; /* skip partition check */	}}static void do_reset1 (ide_drive_t *, int);		/* needed below *//* * atapi_reset_pollfunc() gets invoked to poll the interface for completion every 50ms * during an atapi drive reset operation. If the drive has not yet responded, * and we have not yet hit our maximum waiting time, then the timer is restarted * for another 50ms. */static void atapi_reset_pollfunc (ide_drive_t *drive){	ide_hwgroup_t *hwgroup = HWGROUP(drive);	byte stat;	SELECT_DRIVE(HWIF(drive),drive);	udelay (10);	if (OK_STAT(stat=GET_STAT(), 0, BUSY_STAT)) {		printk("%s: ATAPI reset complete\n", drive->name);	} else {		if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) {			ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20);			return;	/* continue polling */		}		hwgroup->poll_timeout = 0;	/* end of polling */		printk("%s: ATAPI reset timed-out, status=0x%02x\n", drive->name, stat);		do_reset1 (drive, 1);	/* do it the old fashioned way */		return;	}	hwgroup->poll_timeout = 0;	/* done polling */}/* * reset_pollfunc() gets invoked to poll the interface for completion every 50ms * during an ide reset operation. If the drives have not yet responded, * and we have not yet hit our maximum waiting time, then the timer is restarted * for another 50ms. */static void reset_pollfunc (ide_drive_t *drive){	ide_hwgroup_t *hwgroup = HWGROUP(drive);	ide_hwif_t *hwif = HWIF(drive);	byte tmp;	if (!OK_STAT(tmp=GET_STAT(), 0, BUSY_STAT)) {		if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) {			ide_set_handler (drive, &reset_pollfunc, HZ/20);			return;	/* continue polling */		}		printk("%s: reset timed-out, status=0x%02x\n", hwif->name, tmp);	} else  {		printk("%s: reset: ", hwif->name);		if ((tmp = GET_ERR()) == 1)			printk("success\n");		else {#if FANCY_STATUS_DUMPS			printk("master: ");			switch (tmp & 0x7f) {				case 1: printk("passed");					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 */}static void pre_reset (ide_drive_t *drive){	if (!drive->keep_settings) {		drive->unmask = 0;		drive->io_32bit = 0;		if (drive->using_dma)			(void) HWIF(drive)->dmaproc(ide_dma_off, drive);	}	if (drive->driver != NULL)		DRIVER(drive)->pre_reset(drive);}/* * 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);	/* local CPU only */	__cli();		/* local CPU only */	/* For an ATAPI device, first try an ATAPI SRST. */	if (drive->media != ide_disk && !do_not_try_atapi) {		pre_reset(drive);		SELECT_DRIVE(hwif,drive);		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);	/* local CPU only */		return;	}	/*	 * First, reset any device state data we were maintaining	 * for any of the drives on this interface.	 */	for (unit = 0; unit < MAX_DRIVES; ++unit)		pre_reset(&hwif->drives[unit]);#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);	/* local CPU only */}/* * 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);}/* * 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);		}	}	spin_lock_irqsave(&io_request_lock, flags);	drive->queue = rq->next;	blk_dev[MAJOR(rq->rq_dev)].current_request = NULL;	HWGROUP(drive)->rq = NULL;	rq->rq_status = RQ_INACTIVE;	spin_unlock_irqrestore(&io_request_lock, flags);	save_flags(flags);	/* all CPUs; overkill? */	cli();			/* all CPUs; overkill? */	if (rq->sem != NULL)		up(rq->sem);	/* inform originator that rq has been serviced */	restore_flags(flags);	/* all CPUs; overkill? */}/* * 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((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))) {				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);	/* 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) {		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 drive. */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 (drive == NULL || (rq = HWGROUP(drive)->rq) == 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 || ((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;	/* 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;		}		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) {		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;			ide_do_reset(drive);			return;		} else if ((rq->errors & ERROR_RECAL) == ERROR_RECAL)			drive->special.b.recalibrate = 1;		++rq->errors;	}}/* * 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);	OUT_BYTE(drive->ctl,IDE_CONTROL_REG);	/* clear nIEN */	OUT_BYTE(nsect,IDE_NSECTOR_REG);	OUT_BYTE(cmd,IDE_COMMAND_REG);}/*

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -