ide-taskfile.c

来自「ep9315平台下硬盘驱动的源码」· C语言 代码 · 共 2,241 行 · 第 1/5 页

C
2,241
字号
		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) {				/* 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;			}                }media_out:                if ((stat & DRQ_STAT) && rq_data_dir(rq) != WRITE)                        task_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);	} 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(taskfile_error);/* * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd. */ide_startstop_t set_multmode_intr (ide_drive_t *drive){	ide_hwif_t *hwif = HWIF(drive);	u8 stat;	if (OK_STAT(stat = hwif->INB(IDE_STATUS_REG),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;}EXPORT_SYMBOL(set_multmode_intr);/* * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd. */ide_startstop_t set_geometry_intr (ide_drive_t *drive){	ide_hwif_t *hwif = HWIF(drive);	int retries = 5;	u8 stat;	while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--)		udelay(10);	if (OK_STAT(stat, READY_STAT, BAD_STAT))		return ide_stopped;	if (stat & (ERR_STAT|DRQ_STAT))		return DRIVER(drive)->error(drive, "set_geometry_intr", stat);	if (HWGROUP(drive)->handler != NULL)		BUG();	ide_set_handler(drive, &set_geometry_intr, WAIT_WORSTCASE, NULL);	return ide_started;}EXPORT_SYMBOL(set_geometry_intr);/* * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd. */ide_startstop_t recal_intr (ide_drive_t *drive){	ide_hwif_t *hwif = HWIF(drive);	u8 stat;	if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG), READY_STAT, BAD_STAT))		return DRIVER(drive)->error(drive, "recal_intr", stat);	return ide_stopped;}EXPORT_SYMBOL(recal_intr);/* * 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;	ide_hwif_t *hwif	= HWIF(drive);	u8 stat;	local_irq_enable();	if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG),READY_STAT,BAD_STAT)) {		DTF("%s: command opcode 0x%02x\n", drive->name,			args->tfRegister[IDE_COMMAND_OFFSET]);		return DRIVER(drive)->error(drive, "task_no_data_intr", stat);		/* calls ide_end_drive_cmd */	}	if (args)		ide_end_drive_cmd(drive, stat, hwif->INB(IDE_ERROR_REG));	return ide_stopped;}EXPORT_SYMBOL(task_no_data_intr);/* * Handler for command with PIO data-in phase, READ *//* * FIXME before 2.4 enable ... *	DATA integrity issue upon error. <andre@linux-ide.org> */ide_startstop_t task_in_intr (ide_drive_t *drive){	struct request *rq	= HWGROUP(drive)->rq;	ide_hwif_t *hwif	= HWIF(drive);	char *pBuf		= NULL;	u8 stat;	unsigned long flags;	if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG),DATA_READY,BAD_R_STAT)) {		if (stat & (ERR_STAT|DRQ_STAT)) {#if 0			DTF("%s: attempting to recover last " \				"sector counter status=0x%02x\n",				drive->name, stat);			/*			 * Expect a BUG BOMB if we attempt to rewind the			 * offset in the BH aka PAGE in the current BLOCK			 * segment.  This is different than the HOST segment.			 */#endif			if (!rq->bh)				rq->current_nr_sectors++;			return DRIVER(drive)->error(drive, "task_in_intr", stat);		}		if (!(stat & BUSY_STAT)) {			DTF("task_in_intr to Soon wait for next interrupt\n");			if (HWGROUP(drive)->handler == NULL)				ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL);			return ide_started;  		}	}#if 0	/*	 * Holding point for a brain dump of a thought :-/	 */	if (!OK_STAT(stat,DRIVE_READY,drive->bad_wstat)) {		DTF("%s: READ attempting to recover last " \			"sector counter status=0x%02x\n",			drive->name, stat);		rq->current_nr_sectors++;		return DRIVER(drive)->error(drive, "task_in_intr", stat);        }	if (!rq->current_nr_sectors)		if (!DRIVER(drive)->end_request(drive, 1))			return ide_stopped;	if (--rq->current_nr_sectors <= 0)		if (!DRIVER(drive)->end_request(drive, 1))			return ide_stopped;#endif	pBuf = task_map_rq(rq, &flags);	DTF("Read: %p, rq->current_nr_sectors: %d, stat: %02x\n",		pBuf, (int) rq->current_nr_sectors, stat);	taskfile_input_data(drive, pBuf, SECTOR_WORDS);	task_unmap_rq(rq, pBuf, &flags);	/*	 * FIXME :: We really can not legally get a new page/bh	 * regardless, if this is the end of our segment.	 * BH walking or segment can only be updated after we have a good	 * hwif->INB(IDE_STATUS_REG); return.	 */	if (--rq->current_nr_sectors <= 0)		if (!DRIVER(drive)->end_request(drive, 1))			return ide_stopped;	/*	 * ERM, it is techincally legal to leave/exit here but it makes	 * a mess of the code ...	 */	if (HWGROUP(drive)->handler == NULL)		ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL);	return ide_started;}EXPORT_SYMBOL(task_in_intr);/* * Handler for command with Read Multiple */ide_startstop_t task_mulin_intr (ide_drive_t *drive){	ide_hwif_t *hwif	= HWIF(drive);	struct request *rq	= HWGROUP(drive)->rq;	char *pBuf		= NULL;	unsigned int msect	= drive->mult_count;	unsigned int nsect;	unsigned long flags;	u8 stat;	if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG),DATA_READY,BAD_R_STAT)) {		if (stat & (ERR_STAT|DRQ_STAT)) {			if (!rq->bh) {				rq->current_nr_sectors += drive->mult_count;				/*				 * NOTE: could rewind beyond beginning :-/				 */			} else {				printk("%s: MULTI-READ assume all data " \					"transfered is bad status=0x%02x\n",					drive->name, stat);			}			return DRIVER(drive)->error(drive, "task_mulin_intr", stat);		}		/* no data yet, so wait for another interrupt */		if (HWGROUP(drive)->handler == NULL)			ide_set_handler(drive, &task_mulin_intr, WAIT_WORSTCASE, NULL);		return ide_started;	}	do {		nsect = rq->current_nr_sectors;		if (nsect > msect)			nsect = msect;		pBuf = task_map_rq(rq, &flags);		DTF("Multiread: %p, nsect: %d, msect: %d, " \			" rq->current_nr_sectors: %d\n",			pBuf, nsect, msect, rq->current_nr_sectors);		taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);		task_unmap_rq(rq, pBuf, &flags);		rq->errors = 0;		rq->current_nr_sectors -= nsect;		msect -= nsect;		/*		 * FIXME :: We really can not legally get a new page/bh		 * regardless, if this is the end of our segment.		 * BH walking or segment can only be updated after we have a		 * good hwif->INB(IDE_STATUS_REG); return.		 */		if (!rq->current_nr_sectors) {			if (!DRIVER(drive)->end_request(drive, 1))				return ide_stopped;		}	} while (msect);	if (HWGROUP(drive)->handler == NULL)		ide_set_handler(drive, &task_mulin_intr, WAIT_WORSTCASE, NULL);	return ide_started;}EXPORT_SYMBOL(task_mulin_intr);/* * VERIFY ME before 2.4 ... unexpected race is possible based on details * RMK with 74LS245/373/374 TTL buffer logic because of passthrough. */ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq){	char *pBuf		= NULL;	unsigned long flags;	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 WRITE%s\n",			drive->name,			drive->addressing ? "_EXT" : "");		return startstop;	}	/* For Write_sectors we need to stuff the first sector */	pBuf = task_map_rq(rq, &flags);	taskfile_output_data(drive, pBuf, SECTOR_WORDS);	rq->current_nr_sectors--;	task_unmap_rq(rq, pBuf, &flags);	return ide_started;}EXPORT_SYMBOL(pre_task_out_intr);/* * Handler for command with PIO data-out phase WRITE * * WOOHOO this is a CORRECT STATE DIAGRAM NOW, <andre@linux-ide.org> */ide_startstop_t task_out_intr (ide_drive_t *drive){	ide_hwif_t *hwif	= HWIF(drive);	struct request *rq	= HWGROUP(drive)->rq;	char *pBuf		= NULL;	unsigned long flags;	u8 stat;	if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG), DRIVE_READY, drive->bad_wstat)) {		DTF("%s: WRITE attempting to recover last " \			"sector counter status=0x%02x\n",			drive->name, stat);		rq->current_nr_sectors++;		return DRIVER(drive)->error(drive, "task_out_intr", stat);	}	/*	 * Safe to update request for partial completions.	 * We have a good STATUS CHECK!!!	 */	if (!rq->current_nr_sectors)		if (!DRIVER(drive)->end_request(drive, 1))			return ide_stopped;	if ((rq->current_nr_sectors==1) ^ (stat & DRQ_STAT)) {		rq = HWGROUP(drive)->rq;		pBuf = task_map_rq(rq, &flags);		DTF("write: %p, rq->current_nr_sectors: %d\n",			pBuf, (int) rq->current_nr_sectors);		taskfile_output_data(drive, pBuf, SECTOR_WORDS);		task_unmap_rq(rq, pBuf, &flags);		rq->errors = 0;		rq->current_nr_sectors--;	}	if (HWGROUP(drive)->handler == NULL)		ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL);	return ide_started;}EXPORT_SYMBOL(task_out_intr);#undef ALTERNATE_STATE_DIAGRAM_MULTI_OUTide_startstop_t pre_task_mulout_intr (ide_drive_t *drive, struct request *rq){#ifdef ALTERNATE_STATE_DIAGRAM_MULTI_OUT	ide_hwif_t *hwif		= HWIF(drive);	char *pBuf			= NULL;	unsigned int nsect = 0, msect	= drive->mult_count;        u8 stat;	unsigned long flags;#endif /* ALTERNATE_STATE_DIAGRAM_MULTI_OUT */	ide_task_t *args = rq->special;	ide_startstop_t startstop;#if 0	/*	 * assign private copy for multi-write	 */	memcpy(&HWGROUP(drive)->wrq, rq, sizeof(struct request));#endif	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->addressing ? "MULTWRITE_EXT" : "MULTWRITE");		return startstop;	}#ifdef ALTERNATE_STATE_DIAGRAM_MULTI_OUT	do {		nsect = rq->current_nr_sectors;		if (nsect > msect)			nsect = msect;		pBuf = task_map_rq(rq, &flags);		DTF("Pre-Multiwrite: %p, nsect: %d, msect: %d, " \			"rq->current_nr_sectors: %ld\n",			pBuf, nsect, msect, rq->current_nr_sectors);		msect -= nsect;		taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);		task_unmap_rq(rq, pBuf, &flags);		rq->current_nr_sectors -= nsect;		if (!rq->current_nr_sectors) {			if (!DRIVER(drive)->end_request(drive, 1))				if (!rq->bh) {					stat = hwif->INB(IDE_STATUS_REG);					return ide_stopped;				}		}	} while (msect);	rq->errors = 0;	return ide_started;#else /* ! ALTERNATE_STATE_DIAGRAM_MULTI_OUT */	if (!(drive_is_ready(drive))) {		int i;		for (i=0; i<100; i++) {			if (drive_is_ready(drive))				break;		}	}	/*	 * WARNING :: if the drive as not acked good status we may not	 * move the DATA-TRANSFER T-Bar as BSY != 0. <andre@linux-ide.org>	 */	return args->handler(drive);#endif /* ALTERNATE_STATE_DIAGRAM_MULTI_OUT */}EXPORT_SYMBOL(pre_task_mulout_intr);/* * FIXME before enabling in 2.4 ... DATA integrity issue upon error. *//* * Handler for command write multiple * Called directly from execute_drive_cmd for the first bunch of sectors, * afterwards only by the ISR */ide_startstop_t task_mulout_intr (ide_drive_t *drive){	ide_hwif_t *hwif		= HWIF(drive);	u8 stat				= hwif->INB(IDE_STATUS_REG);	struct request *rq		= HWGROUP(drive)->rq;	char *pBuf			= NULL;	ide_startstop_t startstop	= ide_stopped;	unsigned int msect		= drive->mult_count;	unsigned int nsect;	unsigned long flags;	/*	 * (ks/hs): Handle last IRQ on multi-sector transfer,	 * occurs after all data was sent in this chunk	 */	if (rq->current_nr_sectors == 0) {

⌨️ 快捷键说明

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