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

📄 fdc-isr.c

📁 arm平台上的uclinux系统全部源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *      Copyright (C) 1994-1995 Bas Laarhoven. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING.  If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. $Source: /usr/local/cvsroot/AplioTRIO/linux/drivers/char/ftape/fdc-isr.c,v $ $Author: vadim $ * $Revision: 1.1.1.1 $ $Date: 1999/11/15 13:41:57 $ $State: Exp $ * *      This file contains the interrupt service routine and associated *      code for the QIC-40/80 tape streamer device driver. */#include <linux/ftape.h>#include <asm/io.h>#include <asm/dma.h>#define volatile		/* */#include "tracing.h"#include "fdc-isr.h"#include "qic117.h"#include "fdc-io.h"#include "ftape-ctl.h"#include "ftape-rw.h"#include "ftape-io.h"#include "calibr.h"#include "ftape-bsm.h"/*      Global vars. */volatile int expected_stray_interrupts = 0;volatile int seek_completed = 0;volatile int interrupt_seen = 0;volatile int expect_stray_interrupt = 0;int random_rw = 0;/*      Local vars. */typedef enum {	no_error = 0, id_am_error = 0x01, id_crc_error = 0x02,	data_am_error = 0x04, data_crc_error = 0x08,	no_data_error = 0x10, overrun_error = 0x20,} error_cause;static int hide_interrupt;static int stop_read_ahead = 0;static void print_error_cause(int cause){	TRACE_FUN(8, "print_error_cause");	switch (cause) {	case no_data_error:		TRACE(4, "no data error");		break;	case id_am_error:		TRACE(4, "id am error");		break;	case id_crc_error:		TRACE(4, "id crc error");		break;	case data_am_error:		TRACE(4, "data am error");		break;	case data_crc_error:		TRACE(4, "data crc error");		break;	case overrun_error:		TRACE(4, "overrun error");		break;	default:	}	TRACE_EXIT;}static char *get_fdc_mode_text(fdc_mode_enum fdc_mode){	switch (fdc_mode) {	case fdc_idle:		return "fdc_idle";	case fdc_reading_data:		return "fdc_reading_data";	case fdc_seeking:		return "fdc_seeking";	case fdc_writing_data:		return "fdc_writing_data";	case fdc_reading_id:		return "fdc_reading_id";	case fdc_recalibrating:		return "fdc_recalibrating";	default:		return "unknown";	}}static voiddecode_irq_cause(fdc_mode_enum fdc_mode, byte st[],		 char **fdc_mode_txt, error_cause * cause){	TRACE_FUN(8, "decode_irq_cause");	/*  Valid st[], decode cause of interrupt.	 */	*fdc_mode_txt = get_fdc_mode_text(fdc_mode);	switch (st[0] & ST0_INT_MASK) {	case FDC_INT_NORMAL:		TRACEx1(fdc_mode == fdc_reading_id ? 6 : 5,			"normal completion: %s", *fdc_mode_txt);		*cause = no_error;		break;	case FDC_INT_ABNORMAL:		TRACEx1(5, "abnormal completion %s", *fdc_mode_txt);		TRACEx3(6, "ST0: 0x%02x, ST1: 0x%02x, ST2: 0x%02x",			st[0], st[1], st[2]);		TRACEx4(6, "C: 0x%02x, H: 0x%02x, R: 0x%02x, N: 0x%02x",			st[3], st[4], st[5], st[6]);		if (st[1] & 0x01) {			if (st[2] & 0x01) {				*cause = data_am_error;			} else {				*cause = id_am_error;			}		} else if (st[1] & 0x20) {			if (st[2] & 0x20) {				*cause = data_crc_error;			} else {				*cause = id_crc_error;			}		} else if (st[1] & 0x04) {			*cause = no_data_error;		} else if (st[1] & 0x10) {			*cause = overrun_error;		}		print_error_cause(*cause);		break;	case FDC_INT_INVALID:		TRACEx1(5, "invalid completion %s", *fdc_mode_txt);		*cause = no_error;		break;	case FDC_INT_READYCH:		TRACEx1(5, "ready change %s", *fdc_mode_txt);		*cause = no_error;		break;	default:	}	TRACE_EXIT;}static void update_history(error_cause cause){	switch (cause) {	case id_am_error:		history.id_am_errors++;		break;	case id_crc_error:		history.id_crc_errors++;		break;	case data_am_error:		history.data_am_errors++;		break;	case data_crc_error:		history.data_crc_errors++;		break;	case overrun_error:		history.overrun_errors++;		break;	case no_data_error:		history.no_data_errors++;		break;	default:	}}static void skip_bad_sector(buffer_struct * buff){	TRACE_FUN(8, "skip_bad_sector");	/* Mark sector as soft error and skip it	 */	if (buff->remaining > 0) {		++buff->sector_offset;		++buff->data_offset;		--buff->remaining;		buff->ptr += SECTOR_SIZE;		buff->bad_sector_map >>= 1;	} else {		++buff->sector_offset;	/* hack for error maps */		TRACE(1, "skipping last sector in segment");	}	TRACE_EXIT;}static void update_error_maps(buffer_struct * buff, unsigned error_offset){	TRACE_FUN(8, "update_error_maps");	int hard = 0;	/* error_offset is a sector offset !	 */	if (buff->retry < SOFT_RETRIES) {		buff->soft_error_map |= (1 << error_offset);	} else {		buff->hard_error_map |= (1 << error_offset);		buff->soft_error_map &= ~buff->hard_error_map;		buff->retry = -1;	/* will be set to 0 in setup_segment */		hard = 1;	}	TRACEx2(4, "sector %d : %s error", SECTOR(error_offset),		hard ? "hard" : "soft");	TRACEx2(5, "hard map: 0x%08lx, soft map: 0x%08lx",		buff->hard_error_map, buff->soft_error_map);	TRACE_EXIT;}/* *  Error cause:   Amount xferred:  Action: * *  id_am_error         0           mark bad and skip *  id_crc_error        0           mark bad and skip *  data_am_error       0           mark bad and skip *  data_crc_error    % 1024        mark bad and skip *  no_data_error       0           retry on write *                                  mark bad and skip on read *  overrun_error  [ 0..all-1 ]     mark bad and skip *  no_error           all          continue */static void determine_progress(buffer_struct * buff, error_cause cause, int mode){	TRACE_FUN(8, "determine_progress");	unsigned nr_not_xferred;	unsigned nr_xferred;	unsigned dma_residue;	/*  Using less preferred order of disable_dma and get_dma_residue	 *  because this seems to fail on at least one system if reversed!	 */	dma_residue = get_dma_residue(fdc.dma);	disable_dma(fdc.dma);	nr_xferred = buff->sector_count * SECTOR_SIZE - dma_residue;	if (cause == no_error && dma_residue == 0) {		nr_not_xferred = 0;	} else {		if (cause == no_error) {			TRACEx1(4, "unexpected DMA residue: 0x%04x", dma_residue);		} else {			TRACEx1(6, "DMA residue = 0x%04x", dma_residue);		}		nr_not_xferred = ((dma_residue + (SECTOR_SIZE - 1)) / SECTOR_SIZE);		buff->sector_count -= nr_not_xferred;	/* adjust to actual value */	}	/*  Update var's influenced by the DMA operation.	 */	if (buff->sector_count > 0) {		buff->sector_offset += buff->sector_count;		buff->data_offset += buff->sector_count;		buff->ptr += buff->sector_count * SECTOR_SIZE;		buff->remaining -= buff->sector_count;		buff->bad_sector_map >>= buff->sector_count;	}	if (cause == no_error) {		TRACEx1(5, "%d Sector(s) transferred", buff->sector_count);	} else if (cause == no_data_error) {		TRACEx1(5, "Sector %d not found", SECTOR(buff->sector_offset));	} else if (nr_xferred > 0 || cause == id_crc_error ||		   cause == id_am_error || cause == data_am_error) {		TRACEx1(5, "Error in sector %d", SECTOR(buff->sector_offset));	} else if (cause == overrun_error) {		/* got an overrun error on the first byte, must be a hardware problem		 */		TRACE(-1, "Unexpected error: failing DMA controller ?");	} else {		TRACEx1(4, "Unexpected error at sector %d", SECTOR(buff->sector_offset));	}	/*  Sector_offset points to the problem area, except if we got	 *  a data_crc_error. In that case it points one past the failing	 *  sector.	 *  Now adjust sector_offset so it always points one past he	 *  failing sector. I.e. skip the bad sector.	 */	if (cause != no_error) {		if (cause != data_crc_error) {			skip_bad_sector(buff);		}		update_error_maps(buff, buff->sector_offset - 1);	}	TRACE_EXIT;}static int calc_steps(int cmd){	if (current_cylinder > cmd) {		return current_cylinder - cmd;	} else {		return current_cylinder + cmd;	}}static void pause_tape(unsigned segment, int retry, int fdc_mode){	TRACE_FUN(8, "pause_tape");	int result;	/*  The 3rd initializer needs to be explicit or else gcc will	 *  generate a reference to memset :-(	 */	byte out[3] =	{FDC_SEEK, FTAPE_UNIT, 0};	/*  We'll use a raw seek command to get the tape to rewind	 *  and stop for a retry.	 */	++history.rewinds;	if (qic117_cmds[current_command].non_intr) {		TRACE(2, "motion command may be issued too soon");	}	if (retry && (fdc_mode == fdc_reading_data || fdc_mode == fdc_reading_id)) {		current_command = QIC_MICRO_STEP_PAUSE;		might_be_off_track = 1;	} else {		current_command = QIC_PAUSE;	}	out[2] = calc_steps(current_command);	result = fdc_command(out, 3);	/* issue QIC_117 command */	if (result < 0) {		TRACEx1(4, "qic-pause failed, status = %d", result);	} else {		location.known = 0;		runner_status = idle;		hide_interrupt = 1;		tape_running = 0;	}	TRACE_EXIT;}static void stop_tape(unsigned segment){	TRACE_FUN(8, "stop_tape");	int result;	byte out[3] =	{FDC_SEEK, FTAPE_UNIT, calc_steps(QIC_STOP_TAPE)};	if (qic117_cmds[current_command].non_intr) {		TRACE(2, "motion command may be issued too soon");	}	current_command = QIC_STOP_TAPE;	/*  We'll use a raw seek command to get the tape to stop	 */	result = fdc_command(out, 3);	/* issue QIC_117 command */	if (result < 0) {		TRACEx1(4, "qic-stop failed, status = %d", result);	} else {		runner_status = idle;		hide_interrupt = 1;		tape_running = 0;	}	TRACE_EXIT;}static void continue_xfer(buffer_struct ** p_buff, error_cause cause,			  int fdc_mode, unsigned skip){	TRACE_FUN(8, "continue_xfer");	buffer_struct *buff = *p_buff;	int write = (fdc_mode == fdc_writing_data);	byte fdc_op = (write) ? FDC_WRITE : FDC_READ;	if (skip > 0) {		/* This part can be removed if it never happens		 */		if (runner_status != running ||		    (buff->status != (write ? writing : reading))) {			TRACEx2(1, "unexpected runner/buffer state %d/%d",				runner_status, buff->status);			buff->status = error;			*p_buff = next_buffer(&head);	/* finish this buffer */			runner_status = aborting;			fdc_mode = fdc_idle;		}	}	if (buff->remaining > 0 && calc_next_cluster(&buffer[head]) > 0) {		/* still sectors left in current segment, continue with this segment		 */		if (setup_fdc_and_dma(&buffer[head], fdc_op) < 0) {			/* failed, abort operation			 */			buff->bytes = buff->ptr - buff->address;			buff->status = error;			buff = *p_buff = next_buffer(&head);	/* finish this buffer */			runner_status = aborting;			fdc_mode = fdc_idle;		}

⌨️ 快捷键说明

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