ide-io.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,604 行 · 第 1/4 页

C
1,604
字号
				args->hobRegister[IDE_HCYL_OFFSET]	= hwif->INB(IDE_HCYL_REG);			}		}	} else if (blk_pm_request(rq)) {#ifdef DEBUG_PM		printk("%s: complete_power_step(step: %d, stat: %x, err: %x)\n",			drive->name, rq->pm->pm_step, stat, err);#endif		DRIVER(drive)->complete_power_step(drive, rq, stat, err);		if (rq->pm->pm_step == ide_pm_state_completed)			ide_complete_pm_request(drive, rq);		return;	}	spin_lock_irqsave(&ide_lock, flags);	blkdev_dequeue_request(rq);	if (blk_barrier_preflush(rq) || blk_barrier_postflush(rq))		ide_complete_barrier(drive, rq, err);	HWGROUP(drive)->rq = NULL;	end_that_request_last(rq);	spin_unlock_irqrestore(&ide_lock, flags);}EXPORT_SYMBOL(ide_end_drive_cmd);/** *	try_to_flush_leftover_data	-	flush junk *	@drive: drive to flush * *	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 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];		u32 wcount = (i > 16) ? 16 : i;		i -= wcount;		HWIF(drive)->ata_input_data(drive, buffer, wcount);	}}EXPORT_SYMBOL(try_to_flush_leftover_data);/* * FIXME Add an ATAPI error *//** *	ide_error	-	handle an error on the IDE *	@drive: drive the error occurred on *	@msg: message to report *	@stat: status bits * *	ide_error() takes action based on the error returned by the drive. *	For normal I/O that may well include retries. We deal with *	both new-style (taskfile) and old style command handling here. *	In the case of taskfile command handling there is work left to *	do */ ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, u8 stat){	ide_hwif_t *hwif;	struct request *rq;	u8 err;	err = ide_dump_status(drive, msg, stat);	if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)		return ide_stopped;	hwif = HWIF(drive);	/* retry only "normal" I/O: */	if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK)) {		rq->errors = 1;		ide_end_drive_cmd(drive, stat, err);		return ide_stopped;	}	if (rq->flags & REQ_DRIVE_TASKFILE) {		rq->errors = 1;		ide_end_drive_cmd(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)			goto media_out;		if (stat & ERR_STAT) {			/* err has different meaning on cdrom and tape */			if (err == ABRT_ERR) {				if (drive->select.b.lba &&				    (hwif->INB(IDE_COMMAND_REG) == WIN_SPECIFY))					/* some newer drives don't					 * support WIN_SPECIFY					 */					return ide_stopped;			} else if ((err & BAD_CRC) == BAD_CRC) {				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;			}		}media_out:		if ((stat & DRQ_STAT) && rq_data_dir(rq) != WRITE)			try_to_flush_leftover_data(drive);	}	if (hwif->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT)) {		/* force an abort */		hwif->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);	}	if (rq->errors >= ERROR_MAX) {		DRIVER(drive)->end_request(drive, 0, 0);	} 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;}EXPORT_SYMBOL(ide_error);/** *	ide_abort	-	abort pending IDE operatins *	@drive: drive the error occurred on *	@msg: message to report * *	ide_abort kills and cleans up when we are about to do a  *	host initiated reset on active commands. Longer term we *	want handlers to have sensible abort handling themselves * *	This differs fundamentally from ide_error because in  *	this case the command is doing just fine when we *	blow it away. */ ide_startstop_t ide_abort(ide_drive_t *drive, const char *msg){	ide_hwif_t *hwif;	struct request *rq;	if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)		return ide_stopped;	hwif = HWIF(drive);	/* retry only "normal" I/O: */	if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK)) {		rq->errors = 1;		ide_end_drive_cmd(drive, BUSY_STAT, 0);		return ide_stopped;	}	if (rq->flags & REQ_DRIVE_TASKFILE) {		rq->errors = 1;		ide_end_drive_cmd(drive, BUSY_STAT, 0);		return ide_stopped;	}	rq->errors |= ERROR_RESET;	DRIVER(drive)->end_request(drive, 0, 0);	return ide_stopped;}EXPORT_SYMBOL(ide_abort);/** *	ide_cmd		-	issue a simple drive command *	@drive: drive the command is for *	@cmd: command byte *	@nsect: sector byte *	@handler: handler for the command completion * *	Issue a simple drive command with interrupts. *	The drive must be selected beforehand. */void ide_cmd (ide_drive_t *drive, u8 cmd, u8 nsect, ide_handler_t *handler){	ide_hwif_t *hwif = HWIF(drive);	if (IDE_CONTROL_REG)		hwif->OUTB(drive->ctl,IDE_CONTROL_REG);	/* clear nIEN */	SELECT_MASK(drive,0);	hwif->OUTB(nsect,IDE_NSECTOR_REG);	ide_execute_command(drive, cmd, handler, WAIT_CMD, NULL);}EXPORT_SYMBOL(ide_cmd);/** *	drive_cmd_intr		- 	drive command completion interrupt *	@drive: drive the completion interrupt occurred on * *	drive_cmd_intr() is invoked on completion of a special DRIVE_CMD. *	We do any necessary daya reading and then wait for the drive to *	go non busy. At that point we may read the error data and complete *	the request */ ide_startstop_t drive_cmd_intr (ide_drive_t *drive){	struct request *rq = HWGROUP(drive)->rq;	ide_hwif_t *hwif = HWIF(drive);	u8 *args = (u8 *) rq->buffer;	u8 stat = hwif->INB(IDE_STATUS_REG);	int retries = 10;	local_irq_enable();	if ((stat & DRQ_STAT) && args && args[3]) {		u8 io_32bit = drive->io_32bit;		drive->io_32bit = 0;		hwif->ata_input_data(drive, &args[4], args[3] * SECTOR_WORDS);		drive->io_32bit = io_32bit;		while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--)			udelay(100);	}	if (!OK_STAT(stat, READY_STAT, BAD_STAT) && DRIVER(drive) != NULL)		return DRIVER(drive)->error(drive, "drive_cmd", stat);		/* calls ide_end_drive_cmd */	ide_end_drive_cmd(drive, stat, hwif->INB(IDE_ERROR_REG));	return ide_stopped;}EXPORT_SYMBOL(drive_cmd_intr);/** *	do_special		-	issue some special commands *	@drive: drive the command is for * *	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. */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) {		s->b.set_tune = 0;		if (HWIF(drive)->tuneproc != NULL)			HWIF(drive)->tuneproc(drive, drive->tune_req);		return ide_stopped;	}	else		return DRIVER(drive)->special(drive);}EXPORT_SYMBOL(do_special);/** *	execute_drive_command	-	issue special drive command *	@drive: the drive to issue th command on *	@rq: the request structure holding the command * *	execute_drive_cmd() issues a special drive command,  usually  *	initiated by ioctl() from the external hdparm program. The *	command can be a drive command, drive task or taskfile  *	operation. Weirdly you can call it with NULL to wait for *	all commands to finish. Don't do this as that is due to change */ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq){	ide_hwif_t *hwif = HWIF(drive);	if (rq->flags & REQ_DRIVE_TASKFILE) { 		ide_task_t *args = rq->special; 		if (!args)			goto done;		hwif->data_phase = args->data_phase;		if (args->tf_out_flags.all != 0) 			return flagged_taskfile(drive, args);		return do_rw_taskfile(drive, args);	} else if (rq->flags & REQ_DRIVE_TASK) {		u8 *args = rq->buffer;		u8 sel; 		if (!args)			goto done;#ifdef DEBUG 		printk("%s: DRIVE_TASK_CMD ", drive->name); 		printk("cmd=0x%02x ", args[0]); 		printk("fr=0x%02x ", args[1]); 		printk("ns=0x%02x ", args[2]); 		printk("sc=0x%02x ", args[3]); 		printk("lcyl=0x%02x ", args[4]); 		printk("hcyl=0x%02x ", args[5]); 		printk("sel=0x%02x\n", args[6]);#endif 		hwif->OUTB(args[1], IDE_FEATURE_REG); 		hwif->OUTB(args[3], IDE_SECTOR_REG); 		hwif->OUTB(args[4], IDE_LCYL_REG); 		hwif->OUTB(args[5], IDE_HCYL_REG); 		sel = (args[6] & ~0x10); 		if (drive->select.b.unit) 			sel |= 0x10; 		hwif->OUTB(sel, IDE_SELECT_REG); 		ide_cmd(drive, args[0], args[2], &drive_cmd_intr); 		return ide_started; 	} else if (rq->flags & REQ_DRIVE_CMD) { 		u8 *args = rq->buffer;		if (!args)			goto done;#ifdef DEBUG 		printk("%s: DRIVE_CMD ", drive->name); 		printk("cmd=0x%02x ", args[0]); 		printk("sc=0x%02x ", args[1]); 		printk("fr=0x%02x ", args[2]); 		printk("xx=0x%02x\n", args[3]);#endif 		if (args[0] == WIN_SMART) { 			hwif->OUTB(0x4f, IDE_LCYL_REG); 			hwif->OUTB(0xc2, IDE_HCYL_REG); 			hwif->OUTB(args[2],IDE_FEATURE_REG); 			hwif->OUTB(args[1],IDE_SECTOR_REG); 			ide_cmd(drive, args[0], args[3], &drive_cmd_intr); 			return ide_started; 		} 		hwif->OUTB(args[2],IDE_FEATURE_REG); 		ide_cmd(drive, args[0], args[1], &drive_cmd_intr); 		return ide_started; 	}done: 	/* 	 * NULL is actually a valid way of waiting for 	 * all current requests to be flushed from the queue. 	 */#ifdef DEBUG 	printk("%s: DRIVE_CMD (null)\n", drive->name);#endif 	ide_end_drive_cmd(drive,			hwif->INB(IDE_STATUS_REG),			hwif->INB(IDE_ERROR_REG)); 	return ide_stopped;}EXPORT_SYMBOL(execute_drive_cmd);/** *	start_request	-	start of I/O and command issuing for IDE * *	start_request() initiates handling of a new I/O request. It *	accepts commands and I/O (read/write) requests. It also does *	the final remapping for weird stuff like EZDrive. Once  *	device mapper can work sector level the EZDrive stuff can go away * *	FIXME: this function needs a rename */ ide_startstop_t start_request (ide_drive_t *drive, struct request *rq){	ide_startstop_t startstop;	sector_t block;	BUG_ON(!(rq->flags & REQ_STARTED));#ifdef DEBUG	printk("%s: start_request: current=0x%08lx\n",		HWIF(drive)->name, (unsigned long) rq);#endif	/* bail early if we've exceeded max_failures */	if (drive->max_failures && (drive->failures > drive->max_failures)) {		goto kill_rq;	}	/*	 * bail early if we've sent a device to sleep, however how to wake	 * this needs to be a masked flag.  FIXME for proper operations.	 */	if (drive->suspend_reset)

⌨️ 快捷键说明

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