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

📄 ftape-rw.c

📁 arm平台上的uclinux系统全部源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
				 *  and overshoot when seeking backwards.				 */				inhibit_correction = 1;				count += 3;	/* best guess */			}		}	} else {		TRACEx1(5, "warning: zero or negative count: %d", count);	}	if (count > 0) {		int i;		int nibbles = count > 255 ? 3 : 2;		if (count > 4095) {			TRACE(4, "skipping clipped at 4095 segment");			count = 4095;		}		/* Issue this tape command first. */		if (!reverse) {			TRACEx1(4, "skipping %d segment(s)", count);			result = ftape_command(nibbles == 3 ?			   QIC_SKIP_EXTENDED_FORWARD : QIC_SKIP_FORWARD);		} else {			TRACEx1(4, "backing up %d segment(s)", count);			result = ftape_command(nibbles == 3 ?			   QIC_SKIP_EXTENDED_REVERSE : QIC_SKIP_REVERSE);		}		if (result < 0) {			TRACE(4, "Skip command failed");		} else {			--count;	/* 0 means one gap etc. */			for (i = 0; i < nibbles; ++i) {				if (result >= 0) {					result = ftape_parameter(count & 15);					count /= 16;				}			}			result = ftape_ready_wait(timeout.rewind, &status);			if (result >= 0) {				tape_running = 0;			}		}	}	TRACE_EXIT;	return result;}static int validate(int id){	/*  Check to see if position found is off-track as reported once.	 *  Because all tracks in one direction lie next to each other,	 *  if off-track the error will be approximately 2 * segments_per_track.	 */	if (location.track == -1) {		return 1;	/* unforeseen situation, don't generate error */	} else {		/*  Use margin of segments_per_track on both sides because ftape		 *  needs some margin and the error we're looking for is much larger !		 */		int lo = (location.track - 1) * segments_per_track;		int hi = (location.track + 2) * segments_per_track;		return (id >= lo && id < hi);	}}static int seek_forward(int segment_id){	TRACE_FUN(5, "seek_forward");	int failures = 0;	int result = 0;	int count;	static int margin = 1;	/* fixed: stop this before target */	static int overshoot = 1;	static int min_count = 8;	int expected = -1;	int target = segment_id - margin;	int fast_seeking;	if (!location.known) {		TRACE(1, "fatal: cannot seek from unknown location");		result = -EIO;	} else if (!validate(segment_id)) {		TRACE(1, "fatal: head off track (bad hardware?)");		ftape_sleep(1 * SECOND);		ftape_failure = 1;		result = -EIO;	} else {		int prev_segment = location.segment;		TRACEx4(4, "from %d/%d to %d/0 - %d", location.segment,			location.sector, segment_id, margin);		count = target - location.segment - overshoot;		fast_seeking = (count > min_count + (location.bot ? 1 : 0));		if (fast_seeking) {			TRACEx1(5, "fast skipping %d segments", count);			expected = segment_id - margin;			fast_seek(count, 0);		}		if (!tape_running) {			logical_forward();		}		while (location.segment < segment_id) {			/*  This requires at least one sector in a (bad) segment to			 *  have a valid and readable sector id !			 *  It looks like this is not guaranteed, so we must try			 *  to find a way to skip an EMPTY_SEGMENT. !!! FIXME !!!			 */			if (ftape_read_id() < 0 || !location.known) {				location.known = 0;				if (!tape_running || ++failures > SECTORS_PER_SEGMENT ||				    (current->signal & _DONT_BLOCK)) {					TRACE(1, "read_id failed completely");					result = -EIO;					break;				} else {					TRACEx1(5, "read_id failed, retry (%d)", failures);				}			} else if (fast_seeking) {				TRACEx4(4, "ended at %d/%d (%d,%d)", location.segment,					location.sector, overshoot, inhibit_correction);				if (!inhibit_correction &&				    (location.segment < expected ||				 location.segment > expected + margin)) {					int error = location.segment - expected;					TRACEx2(4, "adjusting overshoot from %d to %d",					   overshoot, overshoot + error);					overshoot += error;					/*  All overshoots have the same direction, so it should					 *  never become negative, but who knows.					 */					if (overshoot < -5 || overshoot > 10) {						if (overshoot < 0) {							overshoot = -5;		/* keep sane value */						} else {							overshoot = 10;		/* keep sane value */						}						TRACEx1(4, "clipped overshoot to %d", overshoot);					}				}				fast_seeking = 0;			}			if (location.known) {				if (location.segment > prev_segment + 1) {					TRACEx1(4, "missed segment %d while skipping", prev_segment + 1);				}				prev_segment = location.segment;			}		}		if (location.segment > segment_id) {			TRACEx2(4, "failed: skip ended at segment %d/%d",				location.segment, location.sector);			result = -EIO;		}	}	TRACE_EXIT;	return result;}static int skip_reverse(int segment_id, int *pstatus){	TRACE_FUN(5, "skip_reverse");	int result = 0;	int failures = 0;	static int overshoot = 1;	static int min_rewind = 2;	/* 1 + overshoot */	static const int margin = 1;	/* stop this before target */	int expected = 0;	int count;	int short_seek;	int target = segment_id - margin;	if (location.known && !validate(segment_id)) {		TRACE(1, "fatal: head off track (bad hardware?)");		ftape_sleep(1 * SECOND);		ftape_failure = 1;		result = -EIO;	} else		do {			if (!location.known) {				TRACE(-1, "warning: location not known");			}			TRACEx4(4, "from %d/%d to %d/0 - %d",				location.segment, location.sector, segment_id, margin);			/*  min_rewind == 1 + overshoot_when_doing_minimum_rewind			 *  overshoot  == overshoot_when_doing_larger_rewind			 *  Initially min_rewind == 1 + overshoot, optimization			 *  of both values will be done separately.			 *  overshoot and min_rewind can be negative as both are			 *  sums of three components:			 *  any_overshoot == rewind_overshoot - stop_overshoot - start_overshoot			 */			if (location.segment - target - (min_rewind - 1) < 1) {				short_seek = 1;			} else {				count = location.segment - target - overshoot;				short_seek = (count < 1);			}			if (short_seek) {				count = 1;	/* do shortest rewind */				expected = location.segment - min_rewind;				if (expected / segments_per_track != location.track) {					expected = location.track * segments_per_track;				}			} else {				expected = target;			}			fast_seek(count, 1);			logical_forward();			result = ftape_read_id();			if (result == 0 && location.known) {				TRACEx5(4, "ended at %d/%d (%d,%d,%d)", location.segment,					location.sector, min_rewind, overshoot, inhibit_correction);				if (!inhibit_correction &&				    (location.segment < expected ||				 location.segment > expected + margin)) {					int error = expected - location.segment;					if (short_seek) {						TRACEx2(4, "adjusting min_rewind from %d to %d",							min_rewind, min_rewind + error);						min_rewind += error;						if (min_rewind < -5) {	/* is this right ? FIXME ! */							min_rewind = -5;	/* keep sane value */							TRACEx1(4, "clipped min_rewind to %d", min_rewind);						}					} else {						TRACEx2(4, "adjusting overshoot from %d to %d",							overshoot, overshoot + error);						overshoot += error;						if (overshoot < -5 || overshoot > 10) {							if (overshoot < 0) {								overshoot = -5;		/* keep sane value */							} else {								overshoot = 10;		/* keep sane value */							}							TRACEx1(4, "clipped overshoot to %d", overshoot);						}					}				}			} else {				if ((!tape_running && !location.known) ||				    ++failures > SECTORS_PER_SEGMENT) {					TRACE(1, "read_id failed completely");					result = -EIO;					break;				} else {					TRACEx1(5, "ftape_read_id failed, retry (%d)", failures);				}				result = ftape_report_drive_status(pstatus);				if (result < 0) {					TRACEi(1, "ftape_report_drive_status failed with code", result);					break;				}			}		} while (location.segment > segment_id &&			 (current->signal & _DONT_BLOCK) == 0);	if (location.known) {		TRACEx2(4, "current location: %d/%d", location.segment, location.sector);	}	TRACE_EXIT;	return result;}static int determine_position(void){	TRACE_FUN(5, "determine_position");	int retry = 0;	int fatal = 0;	int status;	int result;	if (!tape_running) {		/*  This should only happen if tape is stopped by isr.		 */		TRACE(5, "waiting for tape stop");		result = ftape_ready_wait(timeout.pause, &status);		if (result < 0) {			TRACE(5, "drive still running (fatal)");			tape_running = 1;	/* ? */		}	} else {		ftape_report_drive_status(&status);	}	if (status & QIC_STATUS_READY) {		/*  Drive must be ready to check error state !		 */		TRACE(5, "drive is ready");		if (status & QIC_STATUS_ERROR) {			int error;			int command;			/*  Report and clear error state, try to continue.			 */			TRACE(5, "error status set");			ftape_report_error(&error, &command, 1);			ftape_ready_wait(timeout.reset, &status);			tape_running = 0;	/* ? */		}		if (check_bot_eot(status)) {			if (location.bot) {				if ((status & QIC_STATUS_READY) == 0) {					/* tape moving away from bot/eot, let's see if we					 * can catch up with the first segment on this track.					 */				} else {					TRACE(5, "start tape from logical bot");					logical_forward();	/* start moving */				}			} else {				if ((status & QIC_STATUS_READY) == 0) {					TRACE(4, "waiting for logical end of track");					result = ftape_ready_wait(timeout.reset, &status);					/* error handling needed ? */				} else {					TRACE(4, "tape at logical end of track");				}			}		} else {			TRACE(5, "start tape");			logical_forward();	/* start moving */			location.known = 0;	/* not cleared by logical forward ! */		}	}	if (!location.known) {		/* tape should be moving now, start reading id's		 */		TRACE(5, "location unknown");		do {			result = ftape_read_id();			if (result < 0) {				/*  read-id somehow failed, tape may have reached end				 *  or some other error happened.				 */				TRACE(5, "read-id failed");				ftape_report_drive_status(&status);				if (status & QIC_STATUS_READY) {					tape_running = 0;					TRACEx1(4, "tape stopped for unknown reason ! status = 0x%02x",						status);					if (status & QIC_STATUS_ERROR) {						fatal = 1;					} else {						if (check_bot_eot(status)) {							result = 0;						} else {							fatal = 1;	/* oops, tape stopped but not at end ! */						}					}				}				result = -EIO;			}		} while (result < 0 && !fatal && ++retry < SECTORS_PER_SEGMENT);	} else {		result = 0;	}	TRACEx1(5, "tape is positioned at segment %d", location.segment);	TRACE_EXIT;	return result;}/*      Get the tape running and position it just before the *      requested segment. *      Seek tape-track and reposition as needed. */int ftape_start_tape(int segment_id, int sector_offset){	TRACE_FUN(5, "ftape_start_tape");	int track = segment_id / segments_per_track;	int result = -EIO;	int status;	static int last_segment = -1;	static int bad_bus_timing = 0;	/* number of segments passing the head between starting the tape	 * and being able to access the first sector.	 */	static int start_offset = 1;	int retry = 0;	/* If sector_offset > 0, seek into wanted segment instead of	 * into previous.	 * This allows error recovery if a part of the segment is bad	 * (erased) causing the tape drive to generate an index pulse	 * thus causing a no-data error before the requested sector	 * is reached.	 */	tape_running = 0;	TRACEx3(4, "target segment: %d/%d%s", segment_id, sector_offset,		buffer[head].retry > 0 ? " retry" : "");	if (buffer[head].retry > 0) {	/* this is a retry */		if (!bad_bus_timing && ftape_data_rate == 1 &&		    history.overrun_errors - overrun_count_offset >= 8) {			ftape_set_data_rate(ftape_data_rate + 1);			bad_bus_timing = 1;			TRACE(2, "reduced datarate because of excessive overrun errors");		}	}	last_segment = segment_id;	if (location.track != track || (might_be_off_track &&					buffer[head].retry == 0)) {		/* current track unknown or not equal to destination		 */		ftape_ready_wait(timeout.seek, &status);		ftape_seek_head_to_track(track);		overrun_count_offset = history.overrun_errors;	}	do {		if (!location.known) {			determine_position();		}		/*  Check if we are able to catch the requested segment in time.		 */		if (location.known && location.segment >= segment_id -		    ((tape_running || location.bot) ? 0 : start_offset)) {			/*  Too far ahead (in or past target segment).			 */			if (tape_running) {				result = stop_tape(&status);				if (result < 0) {					TRACEi(1, "stop tape failed with code", result);					break;				}				TRACE(5, "tape stopped");				tape_running = 0;			}			TRACE(5, "repositioning");			++history.rewinds;			if (segment_id % segments_per_track < start_offset) {				/*  If seeking to first segments on track better do a complete				 *  rewind to logical begin of track to get a more steady tape				 *  motion.				 */				result = ftape_command_wait((location.track & 1) ?						   QIC_PHYSICAL_FORWARD :						    QIC_PHYSICAL_REVERSE,						timeout.rewind, &status);				check_bot_eot(status);	/* update location */			} else {				result = skip_reverse(segment_id - start_offset, &status);			}		}		if (!location.known) {			TRACE(-1, "panic: location not known");			result = -EIO;			if ((current->signal & _DONT_BLOCK) || ftape_failure) {				break;			} else {				continue;			}		}		TRACEx2(4, "current segment: %d/%d", location.segment, location.sector);		/*  We're on the right track somewhere before the wanted segment.		 *  Start tape movement if needed and skip to just before or inside		 *  the requested segment. Keep tape running.		 */		result = 0;		if (location.segment < segment_id -		    ((tape_running || location.bot) ? 0 : start_offset)) {			if (sector_offset > 0) {				result = seek_forward(segment_id);			} else {				result = seek_forward(segment_id - 1);			}		}		if (result == 0 &&		    location.segment != segment_id - (sector_offset > 0 ? 0 : 1)) {			result = -EIO;		}	} while (result < 0 && !ftape_failure &&		 (current->signal & _DONT_BLOCK) == 0 &&		 ++retry <= 5);	if (result < 0) {		TRACE(1, "failed to reposition");	}	TRACE_EXIT;	return result;}

⌨️ 快捷键说明

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