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

📄 ide.c

📁 GNU Mach 微内核源代码, 基于美国卡内基美隆大学的 Mach 研究项目
💻 C
📖 第 1 页 / 共 5 页
字号:
					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 + -