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

📄 ftape-read.c

📁 arm平台上的uclinux系统全部源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *      Copyright (C) 1993-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/ftape-read.c,v $ $Author: vadim $ * $Revision: 1.1.1.1 $ $Date: 1999/11/15 13:41:58 $ $State: Exp $ * *      This file contains the reading code *      for the QIC-117 floppy-tape driver for Linux. */#include <linux/string.h>#include <linux/errno.h>#include <linux/mm.h>#include <linux/ftape.h>#include <asm/segment.h>#include "tracing.h"#include "ftape-read.h"#include "qic117.h"#include "ftape-io.h"#include "ftape-ctl.h"#include "ftape-rw.h"#include "ftape-write.h"#include "ftape-eof.h"#include "ecc.h"#include "ftape-bsm.h"/*      Global vars. *//*      Local vars. */int buf_pos_rd = 0;int buf_len_rd = 0;void ftape_zap_read_buffers(void){	int i;	for (i = 0; i < NR_BUFFERS; ++i) {		/*		 * changed to "fit" with dynamic allocation of tape_buffer. --khp		 */		buffer[i].address = tape_buffer[i];		buffer[i].status = waiting;		buffer[i].bytes = 0;		buffer[i].skip = 0;		buffer[i].retry = 0;	}	buf_len_rd = 0;	buf_pos_rd = 0;	eof_mark = 0;	ftape_state = idle;}static unsigned long convert_sector_map(buffer_struct * buff){	TRACE_FUN(8, "convert_sector_map");	int i = 0;	unsigned long bad_map = get_bad_sector_entry(buff->segment_id);	unsigned long src_map = buff->soft_error_map | buff->hard_error_map;	unsigned long dst_map = 0;	if (bad_map || src_map) {		TRACEx1(5, "bad_map = 0x%08lx", bad_map);		TRACEx1(5, "src_map = 0x%08lx", src_map);	}	while (bad_map) {		while ((bad_map & 1) == 0) {			if (src_map & 1) {				dst_map |= (1 << i);			}			src_map >>= 1;			bad_map >>= 1;			++i;		}		/* (bad_map & 1) == 1 */		src_map >>= 1;		bad_map >>= 1;	}	if (src_map) {		dst_map |= (src_map << i);	}	if (dst_map) {		TRACEx1(5, "dst_map = 0x%08lx", dst_map);	}	TRACE_EXIT;	return dst_map;}int correct_and_copy(unsigned int tail, byte * destination){	TRACE_FUN(8, "correct_and_copy");	struct memory_segment mseg;	int result;	BAD_SECTOR read_bad;	mseg.read_bad = convert_sector_map(&buffer[tail]);	mseg.marked_bad = 0;	/* not used... */	mseg.blocks = buffer[tail].bytes / SECTOR_SIZE;	mseg.data = buffer[tail].address;	/*    If there are no data sectors we can skip this segment.	 */	if (mseg.blocks <= 3) {		TRACE(4, "empty segment");		TRACE_EXIT;		return 0;	}	read_bad = mseg.read_bad;	history.crc_errors += count_ones(read_bad);	result = ecc_correct_data(&mseg);	if (read_bad != 0 || mseg.corrected != 0) {		TRACElx(4, "crc error map:", read_bad);		TRACElx(4, "corrected map:", mseg.corrected);		history.corrected += count_ones(mseg.corrected);	}	if (result == ECC_CORRECTED || result == ECC_OK) {		if (result == ECC_CORRECTED) {			TRACEi(3, "ecc corrected segment:", buffer[tail].segment_id);		}		memcpy(destination, mseg.data, (mseg.blocks - 3) * SECTOR_SIZE);		if ((read_bad ^ mseg.corrected) & mseg.corrected) {			/* sectors corrected without crc errors set */			history.crc_failures++;		}		TRACE_EXIT;		return (mseg.blocks - 3) * SECTOR_SIZE;	} else {		TRACEi(1, "ecc failure on segment", buffer[tail].segment_id);		history.ecc_failures++;		TRACE_EXIT;		return -EAGAIN;	/* should retry */	}	TRACE_EXIT;	return 0;}/*      Read given segment into buffer at address. */int read_segment(unsigned segment_id, byte * address, int *eof_mark,		 int read_ahead){	TRACE_FUN(5, "read_segment");	int read_done = 0;	int result = 0;	int bytes_read = 0;	int retry = 0;	TRACEi(5, "segment_id =", segment_id);	if (ftape_state != reading) {		if (ftape_state == writing) {			ftape_flush_buffers();	/* flush write buffer */			TRACE(5, "calling ftape_abort_operation");			result = ftape_abort_operation();			if (result < 0) {				TRACE(1, "ftape_abort_operation failed");				TRACE_EXIT;				return -EIO;			}		} else {			/* clear remaining read buffers */			ftape_zap_read_buffers();		}		ftape_state = reading;	}	if (segment_id >= segments_per_track * tracks_per_tape) {		TRACE(5, "reading past end of tape");		TRACE_EXIT;		return -ENOSPC;	}	for (;;) {		/*    Search all full buffers for the first matching the wanted segment.		 *    Clear other buffers on the fly.		 */		while (!read_done && buffer[tail].status == done) {			if (buffer[tail].segment_id == segment_id) {				unsigned eof_sector;				unsigned sector_count = 0;				unsigned long bsm = get_bad_sector_entry(segment_id);				int i;				/*        If out buffer is already full, return its contents.				 */				if (buffer[tail].deleted) {					TRACEi(5, "found segment in cache :", segment_id);					TRACE_EXIT;					/*  Return a value that read_header_segment understands.					 *  As this should only occur when searching for the header					 *  segments it shouldn't be misinterpreted elsewhere.					 */					return 0;				}				TRACEi(5, "found segment in cache :", segment_id);				eof_sector = check_for_eof(segment_id);				if (eof_sector > 0) {					TRACEi(5, "end of file mark in sector:", eof_sector);					for (i = 1; i < eof_sector; ++i) {						if ((bsm & 1) == 0) {							++sector_count;						}						bsm >>= 1;					}					*eof_mark = 1;				}				if (eof_sector != 1) {	/* not found or gt 1 */					result = correct_and_copy(tail, address);					TRACEi(5, "segment contains (bytes) :", result);					if (result < 0) {						if (result != -EAGAIN) {							TRACE_EXIT;							return result;						}						/* keep read_done == 0, will trigger ftape_abort_operation						 * because reading wrong segment.						 */						TRACE(1, "ecc failed, retry");						++retry;					} else {						read_done = 1;					}				} else {					read_done = 1;				}				if (eof_sector > 0) {					bytes_read = sector_count * SECTOR_SIZE;					TRACEi(5, "partial read count:", bytes_read);				} else {					bytes_read = result;				}			} else {				TRACEi(5, "zapping segment in cache :", buffer[tail].segment_id);			}			buffer[tail].status = waiting;			next_buffer(&tail);		}		if (!read_done && buffer[tail].status == reading) {			if (buffer[tail].segment_id == segment_id) {				int result = wait_segment(reading);				if (result < 0) {					if (result == -EINTR) {						TRACE_EXIT;						return result;					}					TRACE(1, "wait_segment failed while reading");					ftape_abort_operation();				}			} else {				/*        We're reading the wrong segment, stop runner.				 */				ftape_abort_operation();			}		}		/*    if just passed the last segment on a track, wait for BOT or EOT mark.		 */		if (runner_status == logical_eot) {			int status;			result = ftape_ready_wait(timeout.seek, &status);			if (result < 0) {				TRACE(1, "ftape_ready_wait waiting for eot/bot failed");			}			if ((status & (QIC_STATUS_AT_BOT | QIC_STATUS_AT_EOT)) == 0) {				TRACE(1, "eot/bot not reached");			}			runner_status = end_of_tape;		}		/*    should runner stop ?		 */		if (runner_status == aborting || runner_status == buffer_overrun ||		    runner_status == end_of_tape) {			if (runner_status != end_of_tape &&			 !(runner_status == aborting && !tape_running)) {				ftape_dumb_stop();			}			if (runner_status == aborting) {				if (buffer[head].status == reading || buffer[head].status == error) {					if (buffer[head].status == error) {						history.defects += count_ones(buffer[head].hard_error_map);					}					buffer[head].status = waiting;				}			}			runner_status = idle;	/* aborted ? */		}		/*    If segment to read is empty, do not start runner for it,		 *    but wait for next read call.		 */		if (get_bad_sector_entry(segment_id) == EMPTY_SEGMENT) {			bytes_read = 0;		/* flag empty segment */			read_done = 1;		}		/*  Allow escape from this loop on signal !		 */		if (current->signal & _DONT_BLOCK) {			TRACE(2, "interrupted by non-blockable signal");			TRACE_EXIT;			return -EINTR;		}		/*    If we got a segment: quit, or else retry up to limit.		 */		if (read_done) {			break;		}		if (retry > RETRIES_ON_ECC_ERROR) {			history.defects++;			TRACE(1, "too many retries on ecc failure");			TRACE_EXIT;			return -ENODATA;		}		/*    Now at least one buffer is empty !		 *    Restart runner & tape if needed.		 */		TRACEx3(8, "head: %d, tail: %d, runner_status: %d",			head, tail, runner_status);		TRACEx2(8, "buffer[].status, [head]: %d, [tail]: %d",			buffer[head].status, buffer[tail].status);		if (buffer[tail].status == waiting) {			setup_new_segment(&buffer[head], segment_id, -1);			if (!read_ahead) {				buffer[head].next_segment = 0;	/* disable read-ahead */			}			calc_next_cluster(&buffer[head]);

⌨️ 快捷键说明

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