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

📄 ftape-rw.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *      Copyright (C) 1993-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/ftape-rw.c,v $ * $Revision: 1.7 $ * $Date: 1997/10/28 14:26:49 $ * *      This file contains some common code for the segment read and *      segment write routines for the QIC-117 floppy-tape driver for *      Linux. */#include <linux/string.h>#include <linux/errno.h>#include <linux/ftape.h>#include <linux/qic117.h>#include "../lowlevel/ftape-tracing.h"#include "../lowlevel/ftape-rw.h"#include "../lowlevel/fdc-io.h"#include "../lowlevel/ftape-init.h"#include "../lowlevel/ftape-io.h"#include "../lowlevel/ftape-ctl.h"#include "../lowlevel/ftape-read.h"#include "../lowlevel/ftape-ecc.h"#include "../lowlevel/ftape-bsm.h"/*      Global vars. */int ft_nr_buffers;buffer_struct *ft_buffer[FT_MAX_NR_BUFFERS];static volatile int ft_head;static volatile int ft_tail;	/* not volatile but need same type as head */int fdc_setup_error;location_record ft_location = {-1, 0};volatile int ftape_tape_running;/*      Local vars. */static int overrun_count_offset;static int inhibit_correction;/*  maxmimal allowed overshoot when fast seeking */#define OVERSHOOT_LIMIT 10/*      Increment cyclic buffer nr. */buffer_struct *ftape_next_buffer(ft_buffer_queue_t pos){	switch (pos) {	case ft_queue_head:		if (++ft_head >= ft_nr_buffers) {			ft_head = 0;		}		return ft_buffer[ft_head];	case ft_queue_tail:		if (++ft_tail >= ft_nr_buffers) {			ft_tail = 0;		}		return ft_buffer[ft_tail];	default:		return NULL;	}}int ftape_buffer_id(ft_buffer_queue_t pos){	switch(pos) {	case ft_queue_head: return ft_head;	case ft_queue_tail: return ft_tail;	default: return -1;	}}buffer_struct *ftape_get_buffer(ft_buffer_queue_t pos){	switch(pos) {	case ft_queue_head: return ft_buffer[ft_head];	case ft_queue_tail: return ft_buffer[ft_tail];	default: return NULL;	}}void ftape_reset_buffer(void){	ft_head = ft_tail = 0;}buffer_state_enum ftape_set_state(buffer_state_enum new_state){	buffer_state_enum old_state = ft_driver_state;	ft_driver_state = new_state;	return old_state;}/*      Calculate Floppy Disk Controller and DMA parameters for a segment. *      head:   selects buffer struct in array. *      offset: number of physical sectors to skip (including bad ones). *      count:  number of physical sectors to handle (including bad ones). */static int setup_segment(buffer_struct * buff, 			 int segment_id,			 unsigned int sector_offset, 			 unsigned int sector_count, 			 int retry){	SectorMap offset_mask;	SectorMap mask;	TRACE_FUN(ft_t_any);	buff->segment_id = segment_id;	buff->sector_offset = sector_offset;	buff->remaining = sector_count;	buff->head = segment_id / ftape_segments_per_head;	buff->cyl = (segment_id % ftape_segments_per_head) / ftape_segments_per_cylinder;	buff->sect = (segment_id % ftape_segments_per_cylinder) * FT_SECTORS_PER_SEGMENT + 1;	buff->deleted = 0;	offset_mask = (1 << buff->sector_offset) - 1;	mask = ftape_get_bad_sector_entry(segment_id) & offset_mask;	while (mask) {		if (mask & 1) {			offset_mask >>= 1;	/* don't count bad sector */		}		mask >>= 1;	}	buff->data_offset = count_ones(offset_mask);	/* good sectors to skip */	buff->ptr = buff->address + buff->data_offset * FT_SECTOR_SIZE;	TRACE(ft_t_flow, "data offset = %d sectors", buff->data_offset);	if (retry) {		buff->soft_error_map &= offset_mask;	/* keep skipped part */	} else {		buff->hard_error_map = buff->soft_error_map = 0;	}	buff->bad_sector_map = ftape_get_bad_sector_entry(buff->segment_id);	if (buff->bad_sector_map != 0) {		TRACE(ft_t_noise, "segment: %d, bad sector map: %08lx",			buff->segment_id, (long)buff->bad_sector_map);	} else {		TRACE(ft_t_flow, "segment: %d", buff->segment_id);	}	if (buff->sector_offset > 0) {		buff->bad_sector_map >>= buff->sector_offset;	}	if (buff->sector_offset != 0 || buff->remaining != FT_SECTORS_PER_SEGMENT) {		TRACE(ft_t_flow, "sector offset = %d, count = %d",			buff->sector_offset, buff->remaining);	}	/*    Segments with 3 or less sectors are not written with valid	 *    data because there is no space left for the ecc.  The	 *    data written is whatever happens to be in the buffer.	 *    Reading such a segment will return a zero byte-count.	 *    To allow us to read/write segments with all bad sectors	 *    we fake one readable sector in the segment. This	 *    prevents having to handle these segments in a very	 *    special way.  It is not important if the reading of this	 *    bad sector fails or not (the data is ignored). It is	 *    only read to keep the driver running.	 *	 *    The QIC-40/80 spec. has no information on how to handle	 *    this case, so this is my interpretation.  	 */	if (buff->bad_sector_map == EMPTY_SEGMENT) {		TRACE(ft_t_flow, "empty segment %d, fake first sector good",		      buff->segment_id);		if (buff->ptr != buff->address) {			TRACE(ft_t_bug, "This is a bug: %p/%p",			      buff->ptr, buff->address);		}		buff->bad_sector_map = FAKE_SEGMENT;	}	fdc_setup_error = 0;	buff->next_segment = segment_id + 1;	TRACE_EXIT 0;}/*      Calculate Floppy Disk Controller and DMA parameters for a new segment. */int ftape_setup_new_segment(buffer_struct * buff, int segment_id, int skip){	int result = 0;	static int old_segment_id = -1;	static buffer_state_enum old_ft_driver_state = idle;	int retry = 0;	unsigned offset = 0;	int count = FT_SECTORS_PER_SEGMENT;	TRACE_FUN(ft_t_flow);	TRACE(ft_t_flow, "%s segment %d (old = %d)",	      (ft_driver_state == reading || ft_driver_state == verifying) 	      ? "reading" : "writing",	      segment_id, old_segment_id);	if (ft_driver_state != old_ft_driver_state) {	/* when verifying */		old_segment_id = -1;		old_ft_driver_state = ft_driver_state;	}	if (segment_id == old_segment_id) {		++buff->retry;		++ft_history.retries;		TRACE(ft_t_flow, "setting up for retry nr %d", buff->retry);		retry = 1;		if (skip && buff->skip > 0) {	/* allow skip on retry */			offset = buff->skip;			count -= offset;			TRACE(ft_t_flow, "skipping %d sectors", offset);		}	} else {		buff->retry = 0;		buff->skip = 0;		old_segment_id = segment_id;	}	result = setup_segment(buff, segment_id, offset, count, retry);	TRACE_EXIT result;}/*      Determine size of next cluster of good sectors. */int ftape_calc_next_cluster(buffer_struct * buff){	/* Skip bad sectors.	 */	while (buff->remaining > 0 && (buff->bad_sector_map & 1) != 0) {		buff->bad_sector_map >>= 1;		++buff->sector_offset;		--buff->remaining;	}	/* Find next cluster of good sectors	 */	if (buff->bad_sector_map == 0) {	/* speed up */		buff->sector_count = buff->remaining;	} else {		SectorMap map = buff->bad_sector_map;		buff->sector_count = 0;		while (buff->sector_count < buff->remaining && (map & 1) == 0) {			++buff->sector_count;			map >>= 1;		}	}	return buff->sector_count;}/*  if just passed the last segment on a track, wait for BOT *  or EOT mark. */int ftape_handle_logical_eot(void){	TRACE_FUN(ft_t_flow);	if (ft_runner_status == logical_eot) {		int status;		TRACE(ft_t_noise, "tape at logical EOT");		TRACE_CATCH(ftape_ready_wait(ftape_timeout.seek, &status),);		if ((status & (QIC_STATUS_AT_BOT | QIC_STATUS_AT_EOT)) == 0) {			TRACE_ABORT(-EIO, ft_t_err, "eot/bot not reached");		}		ft_runner_status = end_of_tape;	}	if (ft_runner_status == end_of_tape) {		TRACE(ft_t_noise, "runner stopped because of logical EOT");		ft_runner_status = idle;	}	TRACE_EXIT 0;}static int check_bot_eot(int status){	TRACE_FUN(ft_t_flow);	if (status & (QIC_STATUS_AT_BOT | QIC_STATUS_AT_EOT)) {		ft_location.bot = ((ft_location.track & 1) == 0 ?				(status & QIC_STATUS_AT_BOT) != 0:				(status & QIC_STATUS_AT_EOT) != 0);		ft_location.eot = !ft_location.bot;		ft_location.segment = (ft_location.track +			(ft_location.bot ? 0 : 1)) * ft_segments_per_track - 1;		ft_location.sector = -1;		ft_location.known  = 1;		TRACE(ft_t_flow, "tape at logical %s",		      ft_location.bot ? "bot" : "eot");		TRACE(ft_t_flow, "segment = %d", ft_location.segment);	} else {		ft_location.known = 0;	}	TRACE_EXIT ft_location.known;}/*      Read Id of first sector passing tape head. */static int ftape_read_id(void){	int status;	__u8 out[2];	TRACE_FUN(ft_t_any);	/* Assume tape is running on entry, be able to handle	 * situation where it stopped or is stopping.	 */	ft_location.known = 0;	/* default is location not known */	out[0] = FDC_READID;	out[1] = ft_drive_sel;	TRACE_CATCH(fdc_command(out, 2),);	switch (fdc_interrupt_wait(20 * FT_SECOND)) {	case 0:		if (fdc_sect == 0) {			if (ftape_report_drive_status(&status) >= 0 &&			    (status & QIC_STATUS_READY)) {				ftape_tape_running = 0;				TRACE(ft_t_flow, "tape has stopped");				check_bot_eot(status);			}		} else {			ft_location.known = 1;			ft_location.segment = (ftape_segments_per_head					       * fdc_head					       + ftape_segments_per_cylinder					       * fdc_cyl					       + (fdc_sect - 1)					       / FT_SECTORS_PER_SEGMENT);			ft_location.sector = ((fdc_sect - 1)					      % FT_SECTORS_PER_SEGMENT);			ft_location.eot = ft_location.bot = 0;		}		break;	case -ETIME:		/*  Didn't find id on tape, must be near end: Wait		 *  until stopped.		 */		if (ftape_ready_wait(FT_FOREVER, &status) >= 0) {			ftape_tape_running = 0;			TRACE(ft_t_flow, "tape has stopped");			check_bot_eot(status);		}		break;	default:		/*  Interrupted or otherwise failing		 *  fdc_interrupt_wait() 		 */		TRACE(ft_t_err, "fdc_interrupt_wait failed");		break;	}	if (!ft_location.known) {		TRACE_ABORT(-EIO, ft_t_flow, "no id found");	}	if (ft_location.sector == 0) {		TRACE(ft_t_flow, "passing segment %d/%d",		      ft_location.segment, ft_location.sector);	} else {		TRACE(ft_t_fdc_dma, "passing segment %d/%d",		      ft_location.segment, ft_location.sector);	}

⌨️ 快捷键说明

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