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

📄 ftape-rw.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
	TRACE_EXIT 0;}static int logical_forward(void){	ftape_tape_running = 1;	return ftape_command(QIC_LOGICAL_FORWARD);}int ftape_stop_tape(int *pstatus){	int retry = 0;	int result;	TRACE_FUN(ft_t_flow);	do {		result = ftape_command_wait(QIC_STOP_TAPE,					    ftape_timeout.stop, pstatus);		if (result == 0) {			if ((*pstatus & QIC_STATUS_READY) == 0) {				result = -EIO;			} else {				ftape_tape_running = 0;			}		}	} while (result < 0 && ++retry <= 3);	if (result < 0) {		TRACE(ft_t_err, "failed ! (fatal)");	}	TRACE_EXIT result;}int ftape_dumb_stop(void){	int result;	int status;	TRACE_FUN(ft_t_flow);	/*  Abort current fdc operation if it's busy (probably read	 *  or write operation pending) with a reset.	 */	if (fdc_ready_wait(100 /* usec */) < 0) {		TRACE(ft_t_noise, "aborting fdc operation");		fdc_reset();	}	/*  Reading id's after the last segment on a track may fail	 *  but eventually the drive will become ready (logical eot).	 */	result = ftape_report_drive_status(&status);	ft_location.known = 0;	do {		if (result == 0 && status & QIC_STATUS_READY) {			/* Tape is not running any more.			 */			TRACE(ft_t_noise, "tape already halted");			check_bot_eot(status);			ftape_tape_running = 0;		} else if (ftape_tape_running) {			/*  Tape is (was) still moving.			 */#ifdef TESTING			ftape_read_id();#endif			result = ftape_stop_tape(&status);		} else {			/*  Tape not yet ready but stopped.			 */			result = ftape_ready_wait(ftape_timeout.pause,&status);		}	} while (ftape_tape_running		 && !(sigtestsetmask(&current->pending.signal, _NEVER_BLOCK)));#ifndef TESTING	ft_location.known = 0;#endif	if (ft_runner_status == aborting || ft_runner_status == do_abort) {		ft_runner_status = idle;	}	TRACE_EXIT result;}/*      Wait until runner has finished tail buffer. * */int ftape_wait_segment(buffer_state_enum state){	int status;	int result = 0;	TRACE_FUN(ft_t_flow);	while (ft_buffer[ft_tail]->status == state) {		TRACE(ft_t_flow, "state: %d", ft_buffer[ft_tail]->status);		/*  First buffer still being worked on, wait up to timeout.		 *		 *  Note: we check two times for being killed. 50		 *  seconds are quite long. Note that		 *  fdc_interrupt_wait() is not killable by any		 *  means. ftape_read_segment() wants us to return		 *  -EINTR in case of a signal.  		 */		FT_SIGNAL_EXIT(_DONT_BLOCK);		result = fdc_interrupt_wait(50 * FT_SECOND);		FT_SIGNAL_EXIT(_DONT_BLOCK);		if (result < 0) {			TRACE_ABORT(result,				    ft_t_err, "fdc_interrupt_wait failed");		}		if (fdc_setup_error) {			/* recover... FIXME */			TRACE_ABORT(-EIO, ft_t_err, "setup error");		}	}	if (ft_buffer[ft_tail]->status != error) {		TRACE_EXIT 0;	}	TRACE_CATCH(ftape_report_drive_status(&status),);	TRACE(ft_t_noise, "ftape_report_drive_status: 0x%02x", status);	if ((status & QIC_STATUS_READY) && 	    (status & QIC_STATUS_ERROR)) {		unsigned int error;		qic117_cmd_t command;				/*  Report and clear error state.		 *  In case the drive can't operate at the selected		 *  rate, select the next lower data rate.		 */		ftape_report_error(&error, &command, 1);		if (error == 31 && command == QIC_LOGICAL_FORWARD) {			/* drive does not accept this data rate */			if (ft_data_rate > 250) {				TRACE(ft_t_info,				      "Probable data rate conflict");				TRACE(ft_t_info,				      "Lowering data rate to %d Kbps",				      ft_data_rate / 2);				ftape_half_data_rate();				if (ft_buffer[ft_tail]->retry > 0) {					/* give it a chance */					--ft_buffer[ft_tail]->retry;				}			} else {				/* no rate is accepted... */				TRACE(ft_t_err, "We're dead :(");			}		} else {			TRACE(ft_t_err, "Unknown error");		}		TRACE_EXIT -EIO;   /* g.p. error */	}	TRACE_EXIT 0;}/* forward */ static int seek_forward(int segment_id, int fast);static int fast_seek(int count, int reverse){	int result = 0;	int status;	TRACE_FUN(ft_t_flow);	if (count > 0) {		/*  If positioned at begin or end of tape, fast seeking needs		 *  special treatment.		 *  Starting from logical bot needs a (slow) seek to the first		 *  segment before the high speed seek. Most drives do this		 *  automatically but some older don't, so we treat them		 *  all the same.		 *  Starting from logical eot is even more difficult because		 *  we cannot (slow) reverse seek to the last segment.		 *  TO BE IMPLEMENTED.		 */		inhibit_correction = 0;		if (ft_location.known &&		    ((ft_location.bot && !reverse) ||		     (ft_location.eot && reverse))) {			if (!reverse) {				/*  (slow) skip to first segment on a track				 */				seek_forward(ft_location.track * ft_segments_per_track, 0);				--count;			} else {				/*  When seeking backwards from				 *  end-of-tape the number of erased				 *  gaps found seems to be higher than				 *  expected.  Therefor the drive must				 *  skip some more segments than				 *  calculated, but we don't know how				 *  many.  Thus we will prevent the				 *  re-calculation of offset and				 *  overshoot when seeking backwards.				 */				inhibit_correction = 1;				count += 3;	/* best guess */			}		}	} else {		TRACE(ft_t_flow, "warning: zero or negative count: %d", count);	}	if (count > 0) {		int i;		int nibbles = count > 255 ? 3 : 2;		if (count > 4095) {			TRACE(ft_t_noise, "skipping clipped at 4095 segment");			count = 4095;		}		/* Issue this tape command first. */		if (!reverse) {			TRACE(ft_t_noise, "skipping %d segment(s)", count);			result = ftape_command(nibbles == 3 ?			   QIC_SKIP_EXTENDED_FORWARD : QIC_SKIP_FORWARD);		} else {			TRACE(ft_t_noise, "backing up %d segment(s)", count);			result = ftape_command(nibbles == 3 ?			   QIC_SKIP_EXTENDED_REVERSE : QIC_SKIP_REVERSE);		}		if (result < 0) {			TRACE(ft_t_noise, "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(ftape_timeout.rewind, &status);			if (result >= 0) {				ftape_tape_running = 0;			}		}	}	TRACE_EXIT 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 * ft_segments_per_track.	 */	if (ft_location.track == -1) {		return 1; /* unforseen situation, don't generate error */	} else {		/* Use margin of ft_segments_per_track on both sides		 * because ftape needs some margin and the error we're		 * looking for is much larger !		 */		int lo = (ft_location.track - 1) * ft_segments_per_track;		int hi = (ft_location.track + 2) * ft_segments_per_track;		return (id >= lo && id < hi);	}}static int seek_forward(int segment_id, int fast){	int failures = 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;	int prev_segment = ft_location.segment;	TRACE_FUN(ft_t_flow);	if (!ft_location.known) {		TRACE_ABORT(-EIO, ft_t_err,			    "fatal: cannot seek from unknown location");	}	if (!validate(segment_id)) {		ftape_sleep(1 * FT_SECOND);		ft_failure = 1;		TRACE_ABORT(-EIO, ft_t_err,			    "fatal: head off track (bad hardware?)");	}	TRACE(ft_t_noise, "from %d/%d to %d/0 - %d",	      ft_location.segment, ft_location.sector,segment_id,margin);	count = target - ft_location.segment - overshoot;	fast_seeking = (fast &&			count > (min_count + (ft_location.bot ? 1 : 0)));	if (fast_seeking) {		TRACE(ft_t_noise, "fast skipping %d segments", count);		expected = segment_id - margin;		fast_seek(count, 0);	}	if (!ftape_tape_running) {		logical_forward();	}	while (ft_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 || !ft_location.known ||		    sigtestsetmask(&current->pending.signal, _DONT_BLOCK)) {			ft_location.known = 0;			if (!ftape_tape_running ||			    ++failures > FT_SECTORS_PER_SEGMENT) {				TRACE_ABORT(-EIO, ft_t_err,					    "read_id failed completely");			}			FT_SIGNAL_EXIT(_DONT_BLOCK);			TRACE(ft_t_flow, "read_id failed, retry (%d)",			      failures);			continue;		}		if (fast_seeking) {			TRACE(ft_t_noise, "ended at %d/%d (%d,%d)",			      ft_location.segment, ft_location.sector,			      overshoot, inhibit_correction);			if (!inhibit_correction &&			    (ft_location.segment < expected ||			     ft_location.segment > expected + margin)) {				int error = ft_location.segment - expected;				TRACE(ft_t_noise,				      "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 > OVERSHOOT_LIMIT) {					if (overshoot < 0) {						/* keep sane value */						overshoot = -5;					} else {						/* keep sane value */						overshoot = OVERSHOOT_LIMIT;					}					TRACE(ft_t_noise,					      "clipped overshoot to %d",					      overshoot);				}			}			fast_seeking = 0;		}		if (ft_location.known) {			if (ft_location.segment > prev_segment + 1) {				TRACE(ft_t_noise,				      "missed segment %d while skipping",				      prev_segment + 1);			}			prev_segment = ft_location.segment;		}	}	if (ft_location.segment > segment_id) {		TRACE_ABORT(-EIO,			    ft_t_noise, "failed: skip ended at segment %d/%d",			    ft_location.segment, ft_location.sector);	}	TRACE_EXIT 0;}static int skip_reverse(int segment_id, int *pstatus){	int failures = 0;	static int overshoot = 1;	static int min_rewind = 2;	/* 1 + overshoot */	static const int margin = 1;	/* stop this before target */

⌨️ 快捷键说明

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