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

📄 fdc-isr.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *      Copyright (C) 1994-1996 Bas Laarhoven, *                (C) 1996-1997 Claus-Justus Heine. 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: /homes/cvs/ftape-stacked/ftape/lowlevel/fdc-isr.c,v $ * $Revision: 1.9 $ * $Date: 1997/10/17 23:01:53 $ * *      This file contains the interrupt service routine and *      associated code for the QIC-40/80/3010/3020 floppy-tape driver *      "ftape" for Linux. */#include <asm/io.h>#include <asm/dma.h>#define volatile		/* */#include <linux/ftape.h>#include <linux/qic117.h>#include "../lowlevel/ftape-tracing.h"#include "../lowlevel/fdc-isr.h"#include "../lowlevel/fdc-io.h"#include "../lowlevel/ftape-ctl.h"#include "../lowlevel/ftape-rw.h"#include "../lowlevel/ftape-io.h"#include "../lowlevel/ftape-calibr.h"#include "../lowlevel/ftape-bsm.h"/*      Global vars. */volatile int ft_expected_stray_interrupts;volatile int ft_interrupt_seen;volatile int ft_seek_completed;volatile int ft_hide_interrupt;/*      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 stop_read_ahead;static void print_error_cause(int cause){	TRACE_FUN(ft_t_any);	switch (cause) {	case no_data_error:		TRACE(ft_t_noise, "no data error");		break;	case id_am_error:		TRACE(ft_t_noise, "id am error");		break;	case id_crc_error:		TRACE(ft_t_noise, "id crc error");		break;	case data_am_error:		TRACE(ft_t_noise, "data am error");		break;	case data_crc_error:		TRACE(ft_t_noise, "data crc error");		break;	case overrun_error:		TRACE(ft_t_noise, "overrun error");		break;	default:;	}	TRACE_EXIT;}static char *fdc_mode_txt(fdc_mode_enum mode){	switch (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";	case fdc_formatting:		return "fdc_formatting";	case fdc_verifying:		return "fdc_verifying";	default:		return "unknown";	}}static inline error_cause decode_irq_cause(fdc_mode_enum mode, __u8 st[]){	error_cause cause = no_error;	TRACE_FUN(ft_t_any);	/*  Valid st[], decode cause of interrupt.	 */	switch (st[0] & ST0_INT_MASK) {	case FDC_INT_NORMAL:		TRACE(ft_t_fdc_dma,"normal completion: %s",fdc_mode_txt(mode));		break;	case FDC_INT_ABNORMAL:		TRACE(ft_t_flow, "abnormal completion %s", fdc_mode_txt(mode));		TRACE(ft_t_fdc_dma, "ST0: 0x%02x, ST1: 0x%02x, ST2: 0x%02x",		      st[0], st[1], st[2]);		TRACE(ft_t_fdc_dma,		      "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:		TRACE(ft_t_flow, "invalid completion %s", fdc_mode_txt(mode));		break;	case FDC_INT_READYCH:		if (st[0] & ST0_SEEK_END) {			TRACE(ft_t_flow, "drive poll completed");		} else {			TRACE(ft_t_flow, "ready change %s",fdc_mode_txt(mode));		}		break;	default:		break;	}	TRACE_EXIT cause;}static void update_history(error_cause cause){	switch (cause) {	case id_am_error:		ft_history.id_am_errors++;		break;	case id_crc_error:		ft_history.id_crc_errors++;		break;	case data_am_error:		ft_history.data_am_errors++;		break;	case data_crc_error:		ft_history.data_crc_errors++;		break;	case overrun_error:		ft_history.overrun_errors++;		break;	case no_data_error:		ft_history.no_data_errors++;		break;	default:;	}}static void skip_bad_sector(buffer_struct * buff){	TRACE_FUN(ft_t_any);	/*  Mark sector as soft error and skip it	 */	if (buff->remaining > 0) {		++buff->sector_offset;		++buff->data_offset;		--buff->remaining;		buff->ptr += FT_SECTOR_SIZE;		buff->bad_sector_map >>= 1;	} else {		/*  Hey, what is this????????????? C code: if we shift 		 *  more than 31 bits, we get no shift. That's bad!!!!!!		 */		++buff->sector_offset;	/* hack for error maps */		TRACE(ft_t_warn, "skipping last sector in segment");	}	TRACE_EXIT;}static void update_error_maps(buffer_struct * buff, unsigned int error_offset){	int hard = 0;	TRACE_FUN(ft_t_any);	if (buff->retry < FT_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;	}	TRACE(ft_t_noise, "sector %d : %s error\n"	      KERN_INFO "hard map: 0x%08lx\n"	      KERN_INFO "soft map: 0x%08lx",	      FT_SECTOR(error_offset), hard ? "hard" : "soft",	      (long) buff->hard_error_map, (long) buff->soft_error_map);	TRACE_EXIT;}static void print_progress(buffer_struct *buff, error_cause cause){	TRACE_FUN(ft_t_any);	switch (cause) {	case no_error: 		TRACE(ft_t_flow,"%d Sector(s) transferred", buff->sector_count);		break;	case no_data_error:		TRACE(ft_t_flow, "Sector %d not found",		      FT_SECTOR(buff->sector_offset));		break;	case overrun_error:		/*  got an overrun error on the first byte, must be a		 *  hardware problem		 */		TRACE(ft_t_bug,		      "Unexpected error: failing DMA or FDC controller ?");		break;	case data_crc_error:		TRACE(ft_t_flow, "Error in sector %d",		      FT_SECTOR(buff->sector_offset - 1));		break;	case id_crc_error:	case id_am_error:	case data_am_error:		TRACE(ft_t_flow, "Error in sector %d",		      FT_SECTOR(buff->sector_offset));		break;	default:		TRACE(ft_t_flow, "Unexpected error at sector %d",		      FT_SECTOR(buff->sector_offset));		break;	}	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 *//*  the arg `sector' is returned by the fdc and tells us at which sector we *  are positioned at (relative to starting sector of segment) */static void determine_verify_progress(buffer_struct *buff,				      error_cause cause,				      __u8 sector){	TRACE_FUN(ft_t_any);	if (cause == no_error && sector == 1) {		buff->sector_offset = FT_SECTORS_PER_SEGMENT;		buff->remaining     = 0;		if (TRACE_LEVEL >= ft_t_flow) {			print_progress(buff, cause);		}	} else {		buff->sector_offset = sector - buff->sect;		buff->remaining = FT_SECTORS_PER_SEGMENT - buff->sector_offset;		TRACE(ft_t_noise, "%ssector offset: 0x%04x", 		      (cause == no_error) ? "unexpected " : "",		      buff->sector_offset);		switch (cause) {		case overrun_error:			break;#if 0		case no_data_error:			buff->retry = FT_SOFT_RETRIES;			if (buff->hard_error_map    &&			    buff->sector_offset > 1 &&			    (buff->hard_error_map & 			     (1 << (buff->sector_offset-2)))) {				buff->retry --;			}			break;#endif		default:			buff->retry = FT_SOFT_RETRIES;			break;		}		if (TRACE_LEVEL >= ft_t_flow) {			print_progress(buff, cause);		}		/*  Sector_offset points to the problem area Now adjust		 *  sector_offset so it always points one past he failing		 *  sector. I.e. skip the bad sector.		 */		++buff->sector_offset;		--buff->remaining;		update_error_maps(buff, buff->sector_offset - 1);	}	TRACE_EXIT;}static void determine_progress(buffer_struct *buff,			       error_cause cause,			       __u8 sector){	unsigned int dma_residue;	TRACE_FUN(ft_t_any);	/*  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);	if (cause != no_error || dma_residue != 0) {		TRACE(ft_t_noise, "%sDMA residue: 0x%04x", 		      (cause == no_error) ? "unexpected " : "",		      dma_residue);		/* adjust to actual value: */		if (dma_residue == 0) {			/* this happens sometimes with overrun errors.			 * I don't know whether we could ignore the			 * overrun error. Play save.			 */			buff->sector_count --;		} else {			buff->sector_count -= ((dma_residue + 						(FT_SECTOR_SIZE - 1)) /					       FT_SECTOR_SIZE);		}	}	/*  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 *					  FT_SECTOR_SIZE);		buff->remaining       -= buff->sector_count;		buff->bad_sector_map >>= buff->sector_count;	}	if (TRACE_LEVEL >= ft_t_flow) {		print_progress(buff, cause);	}	if (cause != no_error) {		if (buff->remaining == 0) {			TRACE(ft_t_warn, "foo?\n"			      KERN_INFO "count : %d\n"			      KERN_INFO "offset: %d\n"			      KERN_INFO "soft  : %08x\n"			      KERN_INFO "hard  : %08x",			      buff->sector_count,			      buff->sector_offset,			      buff->soft_error_map,			      buff->hard_error_map);		}		/*  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 != data_crc_error) {			skip_bad_sector(buff);		}		update_error_maps(buff, buff->sector_offset - 1);	}	TRACE_EXIT;}static int calc_steps(int cmd){	if (ftape_current_cylinder > cmd) {		return ftape_current_cylinder - cmd;	} else {		return ftape_current_cylinder + cmd;	}}static void pause_tape(int retry, int mode){	int result;	__u8 out[3] = {FDC_SEEK, ft_drive_sel, 0};	TRACE_FUN(ft_t_any);	/*  We'll use a raw seek command to get the tape to rewind and	 *  stop for a retry.	 */	++ft_history.rewinds;	if (qic117_cmds[ftape_current_command].non_intr) {		TRACE(ft_t_warn, "motion command may be issued too soon");	}	if (retry && (mode == fdc_reading_data ||		      mode == fdc_reading_id   ||		      mode == fdc_verifying)) {		ftape_current_command = QIC_MICRO_STEP_PAUSE;		ftape_might_be_off_track = 1;	} else {		ftape_current_command = QIC_PAUSE;	}	out[2] = calc_steps(ftape_current_command);	result = fdc_command(out, 3); /* issue QIC_117 command */	ftape_current_cylinder = out[ 2];	if (result < 0) {		TRACE(ft_t_noise, "qic-pause failed, status = %d", result);	} else {		ft_location.known  = 0;		ft_runner_status   = idle;		ft_hide_interrupt     = 1;		ftape_tape_running = 0;	}	TRACE_EXIT;}static void continue_xfer(buffer_struct *buff,			  fdc_mode_enum mode, 			  unsigned int skip){	int write = 0; 	TRACE_FUN(ft_t_any);	if (mode == fdc_writing_data || mode == fdc_deleting) {		write = 1;	}	/*  This part can be removed if it never happens	 */	if (skip > 0 &&	    (ft_runner_status != running ||	     (write && (buff->status != writing)) ||	     (!write && (buff->status != reading && 			 buff->status != verifying)))) {		TRACE(ft_t_err, "unexpected runner/buffer state %d/%d",		      ft_runner_status, buff->status);		buff->status = error;		/* finish this buffer: */		(void)ftape_next_buffer(ft_queue_head);		ft_runner_status = aborting;		fdc_mode         = fdc_idle;

⌨️ 快捷键说明

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