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

📄 ide-io.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
		if (err == ABRT_ERR) {			if (drive->select.b.lba &&			    /* some newer drives don't support WIN_SPECIFY */			    hwif->INB(IDE_COMMAND_REG) == WIN_SPECIFY)				return ide_stopped;		} else if ((err & BAD_CRC) == BAD_CRC) {			/* UDMA crc error, just retry the operation */			drive->crc_count++;		} 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_data_dir(rq) == READ &&	    (hwif->host_flags & IDE_HFLAG_ERROR_STOPS_FIFO) == 0)		try_to_flush_leftover_data(drive);	if (rq->errors >= ERROR_MAX || blk_noretry_request(rq)) {		ide_kill_rq(drive, rq);		return ide_stopped;	}	if (hwif->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT))		rq->errors |= ERROR_RESET;	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;}static ide_startstop_t ide_atapi_error(ide_drive_t *drive, struct request *rq, u8 stat, u8 err){	ide_hwif_t *hwif = drive->hwif;	if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) {		/* other bits are useless when BUSY */		rq->errors |= ERROR_RESET;	} else {		/* add decoding error stuff */	}	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) {		ide_kill_rq(drive, rq);	} else {		if ((rq->errors & ERROR_RESET) == ERROR_RESET) {			++rq->errors;			return ide_do_reset(drive);		}		++rq->errors;	}	return ide_stopped;}ide_startstop_t__ide_error(ide_drive_t *drive, struct request *rq, u8 stat, u8 err){	if (drive->media == ide_disk)		return ide_ata_error(drive, rq, stat, err);	return ide_atapi_error(drive, rq, stat, err);}EXPORT_SYMBOL_GPL(__ide_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){	struct request *rq;	u8 err;	err = ide_dump_status(drive, msg, stat);	if ((rq = HWGROUP(drive)->rq) == NULL)		return ide_stopped;	/* retry only "normal" I/O: */	if (!blk_fs_request(rq)) {		rq->errors = 1;		ide_end_drive_cmd(drive, stat, err);		return ide_stopped;	}	if (rq->rq_disk) {		ide_driver_t *drv;		drv = *(ide_driver_t **)rq->rq_disk->private_data;		return drv->error(drive, rq, stat, err);	} else		return __ide_error(drive, rq, stat, err);}EXPORT_SYMBOL_GPL(ide_error);ide_startstop_t __ide_abort(ide_drive_t *drive, struct request *rq){	if (drive->media != ide_disk)		rq->errors |= ERROR_RESET;	ide_kill_rq(drive, rq);	return ide_stopped;}EXPORT_SYMBOL_GPL(__ide_abort);/** *	ide_abort	-	abort pending IDE operations *	@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){	struct request *rq;	if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)		return ide_stopped;	/* retry only "normal" I/O: */	if (!blk_fs_request(rq)) {		rq->errors = 1;		ide_end_drive_cmd(drive, BUSY_STAT, 0);		return ide_stopped;	}	if (rq->rq_disk) {		ide_driver_t *drv;		drv = *(ide_driver_t **)rq->rq_disk->private_data;		return drv->abort(drive, rq);	} else		return __ide_abort(drive, rq);}/** *	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. */static 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);}/** *	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 data reading and then wait for the drive to *	go non busy. At that point we may read the error data and complete *	the request */ static 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_in_hardirq();	if (rq->cmd_type == REQ_TYPE_ATA_CMD &&	    (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))		return ide_error(drive, "drive_cmd", stat);		/* calls ide_end_drive_cmd */	ide_end_drive_cmd(drive, stat, hwif->INB(IDE_ERROR_REG));	return ide_stopped;}static void ide_init_specify_cmd(ide_drive_t *drive, ide_task_t *task){	task->tfRegister[IDE_NSECTOR_OFFSET] = drive->sect;	task->tfRegister[IDE_SECTOR_OFFSET]  = drive->sect;	task->tfRegister[IDE_LCYL_OFFSET]    = drive->cyl;	task->tfRegister[IDE_HCYL_OFFSET]    = drive->cyl>>8;	task->tfRegister[IDE_SELECT_OFFSET]  = ((drive->head-1)|drive->select.all)&0xBF;	task->tfRegister[IDE_COMMAND_OFFSET] = WIN_SPECIFY;	task->handler = &set_geometry_intr;}static void ide_init_restore_cmd(ide_drive_t *drive, ide_task_t *task){	task->tfRegister[IDE_NSECTOR_OFFSET] = drive->sect;	task->tfRegister[IDE_COMMAND_OFFSET] = WIN_RESTORE;	task->handler = &recal_intr;}static void ide_init_setmult_cmd(ide_drive_t *drive, ide_task_t *task){	task->tfRegister[IDE_NSECTOR_OFFSET] = drive->mult_req;	task->tfRegister[IDE_COMMAND_OFFSET] = WIN_SETMULT;	task->handler = &set_multmode_intr;}static ide_startstop_t ide_disk_special(ide_drive_t *drive){	special_t *s = &drive->special;	ide_task_t args;	memset(&args, 0, sizeof(ide_task_t));	args.command_type = IDE_DRIVE_TASK_NO_DATA;	if (s->b.set_geometry) {		s->b.set_geometry = 0;		ide_init_specify_cmd(drive, &args);	} else if (s->b.recalibrate) {		s->b.recalibrate = 0;		ide_init_restore_cmd(drive, &args);	} else if (s->b.set_multmode) {		s->b.set_multmode = 0;		if (drive->mult_req > drive->id->max_multsect)			drive->mult_req = drive->id->max_multsect;		ide_init_setmult_cmd(drive, &args);	} else if (s->all) {		int special = s->all;		s->all = 0;		printk(KERN_ERR "%s: bad special flag: 0x%02x\n", drive->name, special);		return ide_stopped;	}	do_rw_taskfile(drive, &args);	return ide_started;}/* * handle HDIO_SET_PIO_MODE ioctl abusers here, eventually it will go away */static int set_pio_mode_abuse(ide_hwif_t *hwif, u8 req_pio){	switch (req_pio) {	case 202:	case 201:	case 200:	case 102:	case 101:	case 100:		return (hwif->host_flags & IDE_HFLAG_ABUSE_DMA_MODES) ? 1 : 0;	case 9:	case 8:		return (hwif->host_flags & IDE_HFLAG_ABUSE_PREFETCH) ? 1 : 0;	case 7:	case 6:		return (hwif->host_flags & IDE_HFLAG_ABUSE_FAST_DEVSEL) ? 1 : 0;	default:		return 0;	}}/** *	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. */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_hwif_t *hwif = drive->hwif;		u8 req_pio = drive->tune_req;		s->b.set_tune = 0;		if (set_pio_mode_abuse(drive->hwif, req_pio)) {			if (hwif->set_pio_mode == NULL)				return ide_stopped;			/*			 * take ide_lock for drive->[no_]unmask/[no_]io_32bit			 */			if (req_pio == 8 || req_pio == 9) {				unsigned long flags;				spin_lock_irqsave(&ide_lock, flags);				hwif->set_pio_mode(drive, req_pio);				spin_unlock_irqrestore(&ide_lock, flags);			} else				hwif->set_pio_mode(drive, req_pio);		} else {			int keep_dma = drive->using_dma;			ide_set_pio(drive, req_pio);			if (hwif->host_flags & IDE_HFLAG_SET_PIO_MODE_KEEP_DMA) {				if (keep_dma)					hwif->ide_dma_on(drive);			}		}		return ide_stopped;	} else {		if (drive->media == ide_disk)			return ide_disk_special(drive);		s->all = 0;		drive->mult_req = 0;		return ide_stopped;	}}void ide_map_sg(ide_drive_t *drive, struct request *rq){	ide_hwif_t *hwif = drive->hwif;	struct scatterlist *sg = hwif->sg_table;	if (hwif->sg_mapped)	/* needed by ide-scsi */		return;	if (rq->cmd_type != REQ_TYPE_ATA_TASKFILE) {		hwif->sg_nents = blk_rq_map_sg(drive->queue, rq, sg);	} else {		sg_init_one(sg, rq->buffer, rq->nr_sectors * SECTOR_SIZE);		hwif->sg_nents = 1;	}}EXPORT_SYMBOL_GPL(ide_map_sg);void ide_init_sg_cmd(ide_drive_t *drive, struct request *rq){	ide_hwif_t *hwif = drive->hwif;	hwif->nsect = hwif->nleft = rq->nr_sectors;	hwif->cursg_ofs = 0;	hwif->cursg = NULL;}EXPORT_SYMBOL_GPL(ide_init_sg_cmd);/** *	execute_drive_command	-	issue special drive command *	@drive: the drive to issue the 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 */static ide_startstop_t execute_drive_cmd (ide_drive_t *drive,		struct request *rq){	ide_hwif_t *hwif = HWIF(drive);	if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) { 		ide_task_t *args = rq->special; 		if (!args)			goto done;		hwif->data_phase = args->data_phase;		switch (hwif->data_phase) {		case TASKFILE_MULTI_OUT:		case TASKFILE_OUT:		case TASKFILE_MULTI_IN:		case TASKFILE_IN:			ide_init_sg_cmd(drive, rq);			ide_map_sg(drive, rq);		default:			break;		}		if (args->tf_out_flags.all != 0) 			return flagged_taskfile(drive, args);		return do_rw_taskfile(drive, args);	} else if (rq->cmd_type == REQ_TYPE_ATA_TASK) {		u8 *args = rq->buffer; 		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]);

⌨️ 快捷键说明

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