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

📄 ide-taskfile.c

📁 at91rm9200处理器ide接口驱动程序源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	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 = task_read_24(drive);					OUT_BYTE(0x80, IDE_CONTROL_REG);					high = task_read_24(drive);					sectors = ((__u64)high << 24) | low;					printk(", LBAsect=%lld", sectors);				} 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)->rq)					printk(", sector=%llu", (__u64) HWGROUP(drive)->rq->sector);			}		}#endif  /* FANCY_STATUS_DUMPS */		printk("\n");	}	__restore_flags (flags);	/* local CPU only */	return err;}/* * Clean up after success/failure of an explicit taskfile operation. */void ide_end_taskfile (ide_drive_t *drive, byte stat, byte err){	unsigned long flags;	struct request *rq;	ide_task_t *args;	task_ioreg_t command;	spin_lock_irqsave(&io_request_lock, flags);	rq = HWGROUP(drive)->rq;	spin_unlock_irqrestore(&io_request_lock, flags);	args = (ide_task_t *) rq->special;	command = args->tfRegister[IDE_COMMAND_OFFSET];	rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);	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);	}/*	taskfile_settings_update(drive, args, command); */	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);}/* * 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 task_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;		taskfile_input_data (drive, buffer, wcount);	}}/* * taskfile_error() takes action based on the error returned by the drive. */ide_startstop_t taskfile_error (ide_drive_t *drive, const char *msg, byte stat){	struct request *rq;	byte err;        err = taskfile_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_TASKFILE) {		rq->errors = 1;		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)                        task_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;}#endif/* * Handler for special commands without a data phase from ide-disk *//* * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd. */ide_startstop_t set_multmode_intr (ide_drive_t *drive){	byte stat;	if (OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT)) {		drive->mult_count = drive->mult_req;	} else {		drive->mult_req = drive->mult_count = 0;		drive->special.b.recalibrate = 1;		(void) ide_dump_status(drive, "set_multmode", stat);	}	return ide_stopped;}/* * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd. */ide_startstop_t set_geometry_intr (ide_drive_t *drive){	byte stat;	if (OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT))		return ide_stopped;	if (stat & (ERR_STAT|DRQ_STAT))		return ide_error(drive, "set_geometry_intr", stat);	ide_set_handler(drive, &set_geometry_intr, WAIT_CMD, NULL);	return ide_started;}/* * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd. */ide_startstop_t recal_intr (ide_drive_t *drive){	byte stat = GET_STAT();	if (!OK_STAT(stat,READY_STAT,BAD_STAT))		return ide_error(drive, "recal_intr", stat);	return ide_stopped;}/* * Handler for commands without a data phase */ide_startstop_t task_no_data_intr (ide_drive_t *drive){	ide_task_t *args	= HWGROUP(drive)->rq->special;	byte stat		= GET_STAT();	ide__sti();	/* local CPU only */	if (!OK_STAT(stat, READY_STAT, BAD_STAT))		return ide_error(drive, "task_no_data_intr", stat); /* calls ide_end_drive_cmd */	if (args)		ide_end_drive_cmd (drive, stat, GET_ERR());	return ide_stopped;}/* * Handler for command with PIO data-in phase */ide_startstop_t task_in_intr (ide_drive_t *drive){	byte stat		= GET_STAT();	byte io_32bit		= drive->io_32bit;	struct request *rq	= HWGROUP(drive)->rq;	char *pBuf		= NULL;	if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {		if (stat & (ERR_STAT|DRQ_STAT)) {			return ide_error(drive, "task_in_intr", stat);		}		if (!(stat & BUSY_STAT)) {			DTF("task_in_intr to Soon wait for next interrupt\n");			ide_set_handler(drive, &task_in_intr, WAIT_CMD, NULL);			return ide_started;  		}	}	DTF("stat: %02x\n", stat);	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);	DTF("Read: %p, rq->current_nr_sectors: %d\n", pBuf, (int) rq->current_nr_sectors);	drive->io_32bit = 0;	taskfile_input_data(drive, pBuf, SECTOR_WORDS);	drive->io_32bit = io_32bit;	if (--rq->current_nr_sectors <= 0) {		/* (hs): swapped next 2 lines */		DTF("Request Ended stat: %02x\n", GET_STAT());		ide_end_request(1, HWGROUP(drive));	} else {		ide_set_handler(drive, &task_in_intr,  WAIT_CMD, NULL);		return ide_started;	}	return ide_stopped;}#undef ALTSTAT_SCREW_UP#ifdef ALTSTAT_SCREW_UP/* * (ks/hs): Poll Alternate Status Register to ensure * that drive is not busy. */byte altstat_multi_busy (ide_drive_t *drive, byte stat, const char *msg){	int i;	DTF("multi%s: ASR = %x\n", msg, stat);	if (stat & BUSY_STAT) {		/* (ks/hs): FIXME: Replace hard-coded 100, error handling? */		for (i=0; i<100; i++) {			stat = GET_ALTSTAT();			if ((stat & BUSY_STAT) == 0)				break;		}	}	/*	 * (ks/hs): Read Status AFTER Alternate Status Register	 */	return(GET_STAT());}/* * (ks/hs): Poll Alternate status register to wait for drive * to become ready for next transfer */byte altstat_multi_poll (ide_drive_t *drive, byte stat, const char *msg){	/* (ks/hs): FIXME: Error handling, time-out? */	while (stat & BUSY_STAT)		stat = GET_ALTSTAT();	DTF("multi%s: nsect=1, ASR = %x\n", msg, stat);	return(GET_STAT());	/* (ks/hs): Clear pending IRQ */}#endif /* ALTSTAT_SCREW_UP *//* * Handler for command with Read Multiple */ide_startstop_t task_mulin_intr (ide_drive_t *drive){	unsigned int		msect, nsect;#ifdef ALTSTAT_SCREW_UP	byte stat	= altstat_multi_busy(drive, GET_ALTSTAT(), "read");#else	byte stat		= GET_STAT();#endif /* ALTSTAT_SCREW_UP */	byte io_32bit		= drive->io_32bit;	struct request *rq	= HWGROUP(drive)->rq;	char *pBuf		= NULL;	if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {		if (stat & (ERR_STAT|DRQ_STAT)) {			return ide_error(drive, "task_mulin_intr", stat);		}		/* no data yet, so wait for another interrupt */		ide_set_handler(drive, &task_mulin_intr, WAIT_CMD, NULL);		return ide_started;	}	/* (ks/hs): Fixed Multi-Sector transfer */	msect = drive->mult_count;#ifdef ALTSTAT_SCREW_UP	/*	 * Screw the request we do not support bad data-phase setups!	 * Either read and learn the ATA standard or crash yourself!	 */	if (!msect) {		/*		 * (ks/hs): Drive supports multi-sector transfer,		 * drive->mult_count was not set		 */		nsect = 1;		while (rq->current_nr_sectors) {			pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);			DTF("Multiread: %p, nsect: %d, rq->current_nr_sectors: %ld\n", pBuf, nsect, rq->current_nr_sectors);			drive->io_32bit = 0;			taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);			drive->io_32bit = io_32bit;			rq->errors = 0;			rq->current_nr_sectors -= nsect;			stat = altstat_multi_poll(drive, GET_ALTSTAT(), "read");		}		ide_end_request(1, HWGROUP(drive));		return ide_stopped;	}#endif /* ALTSTAT_SCREW_UP */	nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors;	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);	DTF("Multiread: %p, nsect: %d , rq->current_nr_sectors: %ld\n",		pBuf, nsect, rq->current_nr_sectors);	drive->io_32bit = 0;	taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);	drive->io_32bit = io_32bit;	rq->errors = 0;	rq->current_nr_sectors -= nsect;	if (rq->current_nr_sectors != 0) {		ide_set_handler(drive, &task_mulin_intr, WAIT_CMD, NULL);		return ide_started;	}	ide_end_request(1, HWGROUP(drive));	return ide_stopped;}ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq){	ide_task_t *args = rq->special;	ide_startstop_t startstop;	if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {		printk(KERN_ERR "%s: no DRQ after issuing %s\n", drive->name, drive->mult_count ? "MULTWRITE" : "WRITE");		return startstop;	}	/* (ks/hs): Fixed Multi Write */	if ((args->tfRegister[IDE_COMMAND_OFFSET] != WIN_MULTWRITE) &&	    (args->tfRegister[IDE_COMMAND_OFFSET] != WIN_MULTWRITE_EXT)) {		/* For Write_sectors we need to stuff the first sector */

⌨️ 快捷键说明

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