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

📄 fdc-isr.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
	} else if (buff->remaining > 0 && ftape_calc_next_cluster(buff) > 0) {		/*  still sectors left in current segment, continue		 *  with this segment		 */		if (fdc_setup_read_write(buff, mode) < 0) {			/* failed, abort operation			 */			buff->bytes = buff->ptr - buff->address;			buff->status = error;			/* finish this buffer: */			(void)ftape_next_buffer(ft_queue_head);			ft_runner_status = aborting;			fdc_mode         = fdc_idle;		}	} else {		/* current segment completed		 */		unsigned int last_segment = buff->segment_id;		int eot = ((last_segment + 1) % ft_segments_per_track) == 0;		unsigned int next = buff->next_segment;	/* 0 means stop ! */		buff->bytes = buff->ptr - buff->address;		buff->status = done;		buff = ftape_next_buffer(ft_queue_head);		if (eot) {			/*  finished last segment on current track,			 *  can't continue			 */			ft_runner_status = logical_eot;			fdc_mode         = fdc_idle;			TRACE_EXIT;		}		if (next <= 0) {			/*  don't continue with next segment			 */			TRACE(ft_t_noise, "no %s allowed, stopping tape",			      (write) ? "write next" : "read ahead");			pause_tape(0, mode);			ft_runner_status = idle;  /*  not quite true until						   *  next irq 						   */			TRACE_EXIT;		}		/*  continue with next segment		 */		if (buff->status != waiting) {			TRACE(ft_t_noise, "all input buffers %s, pausing tape",			      (write) ? "empty" : "full");			pause_tape(0, mode);			ft_runner_status = idle;  /*  not quite true until						   *  next irq 						   */			TRACE_EXIT;		}		if (write && next != buff->segment_id) {			TRACE(ft_t_noise, 			      "segments out of order, aborting write");			ft_runner_status = do_abort;			fdc_mode         = fdc_idle;			TRACE_EXIT;		}		ftape_setup_new_segment(buff, next, 0);		if (stop_read_ahead) {			buff->next_segment = 0;			stop_read_ahead = 0;		}		if (ftape_calc_next_cluster(buff) == 0 ||		    fdc_setup_read_write(buff, mode) != 0) {			TRACE(ft_t_err, "couldn't start %s-ahead",			      write ? "write" : "read");			ft_runner_status = do_abort;			fdc_mode         = fdc_idle;		} else {			/* keep on going */			switch (ft_driver_state) {			case   reading: buff->status = reading;   break;			case verifying: buff->status = verifying; break;			case   writing: buff->status = writing;   break;			case  deleting: buff->status = deleting;  break;			default:				TRACE(ft_t_err, 		      "BUG: ft_driver_state %d should be one out of "		      "{reading, writing, verifying, deleting}",				      ft_driver_state);				buff->status = write ? writing : reading;				break;			}		}	}	TRACE_EXIT;}static void retry_sector(buffer_struct *buff, 			 int mode,			 unsigned int skip){	TRACE_FUN(ft_t_any);	TRACE(ft_t_noise, "%s error, will retry",	      (mode == fdc_writing_data || mode == fdc_deleting) ? "write" : "read");	pause_tape(1, mode);	ft_runner_status = aborting;	buff->status     = error;	buff->skip       = skip;	TRACE_EXIT;}static unsigned int find_resume_point(buffer_struct *buff){	int i = 0;	SectorMap mask;	SectorMap map;	TRACE_FUN(ft_t_any);	/*  This function is to be called after all variables have been	 *  updated to point past the failing sector.	 *  If there are any soft errors before the failing sector,	 *  find the first soft error and return the sector offset.	 *  Otherwise find the last hard error.	 *  Note: there should always be at least one hard or soft error !	 */	if (buff->sector_offset < 1 || buff->sector_offset > 32) {		TRACE(ft_t_bug, "BUG: sector_offset = %d",		      buff->sector_offset);		TRACE_EXIT 0;	}	if (buff->sector_offset >= 32) { /* C-limitation on shift ! */		mask = 0xffffffff;	} else {		mask = (1 << buff->sector_offset) - 1;	}	map = buff->soft_error_map & mask;	if (map) {		while ((map & (1 << i)) == 0) {			++i;		}		TRACE(ft_t_noise, "at sector %d", FT_SECTOR(i));	} else {		map = buff->hard_error_map & mask;		i = buff->sector_offset - 1;		if (map) {			while ((map & (1 << i)) == 0) {				--i;			}			TRACE(ft_t_noise, "after sector %d", FT_SECTOR(i));			++i; /* first sector after last hard error */		} else {			TRACE(ft_t_bug, "BUG: no soft or hard errors");		}	}	TRACE_EXIT i;}/*  check possible dma residue when formatting, update position record in *  buffer struct. This is, of course, modelled after determine_progress(), but *  we don't need to set up for retries because the format process cannot be *  interrupted (except at the end of the tape track). */static int determine_fmt_progress(buffer_struct *buff, error_cause cause){	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_info, "DMA residue = 0x%04x", dma_residue);		fdc_mode = fdc_idle;		switch(cause) {		case no_error:			ft_runner_status = aborting;			buff->status = idle;			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 controller ?");			ft_runner_status = do_abort;			buff->status = error;			break;		default:			TRACE(ft_t_noise, "Unexpected error at segment %d",			      buff->segment_id);			ft_runner_status = do_abort;			buff->status = error;			break;		}		TRACE_EXIT -EIO; /* can only retry entire track in format mode				  */	}	/*  Update var's influenced by the DMA operation.	 */	buff->ptr             += FT_SECTORS_PER_SEGMENT * 4;	buff->bytes           -= FT_SECTORS_PER_SEGMENT * 4;	buff->remaining       -= FT_SECTORS_PER_SEGMENT;	buff->segment_id ++; /* done with segment */	TRACE_EXIT 0;}/* *  Continue formatting, switch buffers if there is no data left in *  current buffer. This is, of course, modelled after *  continue_xfer(), but we don't need to set up for retries because *  the format process cannot be interrupted (except at the end of the *  tape track). */static void continue_formatting(buffer_struct *buff){	TRACE_FUN(ft_t_any);	if (buff->remaining <= 0) { /*  no space left in dma buffer */		unsigned int next = buff->next_segment; 		if (next == 0) { /* end of tape track */			buff->status     = done;			ft_runner_status = logical_eot;			fdc_mode         = fdc_idle;			TRACE(ft_t_noise, "Done formatting track %d",			      ft_location.track);			TRACE_EXIT;		}		/*		 *  switch to next buffer!		 */		buff->status   = done;		buff = ftape_next_buffer(ft_queue_head);		if (buff->status != waiting  || next != buff->segment_id) {			goto format_setup_error;		}	}	if (fdc_setup_formatting(buff) < 0) {		goto format_setup_error;	}	buff->status = formatting;	TRACE(ft_t_fdc_dma, "Formatting segment %d on track %d",	      buff->segment_id, ft_location.track);	TRACE_EXIT; format_setup_error:	ft_runner_status = do_abort;	fdc_mode         = fdc_idle;	buff->status     = error;	TRACE(ft_t_err, "Error setting up for segment %d on track %d",	      buff->segment_id, ft_location.track);	TRACE_EXIT;}/*  this handles writing, read id, reading and formatting */static void handle_fdc_busy(buffer_struct *buff){	static int no_data_error_count;	int retry = 0;	error_cause cause;	__u8 in[7];	int skip;	fdc_mode_enum fmode = fdc_mode;	TRACE_FUN(ft_t_any);	if (fdc_result(in, 7) < 0) { /* better get it fast ! */		TRACE(ft_t_err, 		      "Probably fatal error during FDC Result Phase\n"		      KERN_INFO		      "drive may hang until (power on) reset :-(");		/*  what to do next ????		 */		TRACE_EXIT;	}	cause = decode_irq_cause(fdc_mode, in);#ifdef TESTING	{ int i;	for (i = 0; i < (int)ft_nr_buffers; ++i)		TRACE(ft_t_any, "buffer[%d] status: %d, segment_id: %d",		      i, ft_buffer[i]->status, ft_buffer[i]->segment_id);	}#endif	if (fmode == fdc_reading_data && ft_driver_state == verifying) {		fmode = fdc_verifying;	}	switch (fmode) {	case fdc_verifying:		if (ft_runner_status == aborting ||		    ft_runner_status == do_abort) {			TRACE(ft_t_noise,"aborting %s",fdc_mode_txt(fdc_mode));			break;		}		if (buff->retry > 0) {			TRACE(ft_t_flow, "this is retry nr %d", buff->retry);		}		switch (cause) {		case no_error:			no_data_error_count = 0;			determine_verify_progress(buff, cause, in[5]);			if (in[2] & 0x40) {				/*  This should not happen when verifying				 */				TRACE(ft_t_warn,				      "deleted data in segment %d/%d",				      buff->segment_id,				      FT_SECTOR(buff->sector_offset - 1));				buff->remaining = 0; /* abort transfer */				buff->hard_error_map = EMPTY_SEGMENT;				skip = 1;			} else {				skip = 0;			}			continue_xfer(buff, fdc_mode, skip);			break;		case no_data_error:			no_data_error_count ++;		case overrun_error:			retry ++;		case id_am_error:		case id_crc_error:		case data_am_error:		case data_crc_error:			determine_verify_progress(buff, cause, in[5]); 			if (cause == no_data_error) {				if (no_data_error_count >= 2) {					TRACE(ft_t_warn,					      "retrying because of successive "					      "no data errors");					no_data_error_count = 0;				} else {					retry --;				}			} else {				no_data_error_count = 0;			}			if (retry) {				skip = find_resume_point(buff);			} else {				skip = buff->sector_offset;			}			if (retry && skip < 32) {				retry_sector(buff, fdc_mode, skip);			} else {				continue_xfer(buff, fdc_mode, skip);			}			update_history(cause);			break;		default:			/*  Don't know why this could happen 			 *  but find out.			 */			determine_verify_progress(buff, cause, in[5]);			retry_sector(buff, fdc_mode, 0);			TRACE(ft_t_err, "Error: unexpected error");			break;		}		break;	case fdc_reading_data:#ifdef TESTING		/* I'm sorry, but: NOBODY ever used this trace		 * messages for ages. I guess that Bas was the last person		 * that ever really used this (thank you, between the lines)		 */		if (cause == no_error) {			TRACE(ft_t_flow,"reading segment %d",buff->segment_id);		} else {			TRACE(ft_t_noise, "error reading segment %d",			      buff->segment_id);			TRACE(ft_t_noise, "\n"			      KERN_INFO			     "IRQ:C: 0x%02x, H: 0x%02x, R: 0x%02x, N: 0x%02x\n"			      KERN_INFO			      "BUF:C: 0x%02x, H: 0x%02x, R: 0x%02x",			      in[3], in[4], in[5], in[6],			      buff->cyl, buff->head, buff->sect);		}#endif		if (ft_runner_status == aborting ||		    ft_runner_status == do_abort) {			TRACE(ft_t_noise,"aborting %s",fdc_mode_txt(fdc_mode));			break;		}		if (buff->bad_sector_map == FAKE_SEGMENT) {			/* This condition occurs when reading a `fake'			 * sector that's not accessible. Doesn't			 * really matter as we would have ignored it			 * anyway !			 *			 * Chance is that we're past the next segment			 * now, so the next operation may fail and			 * result in a retry.  			 */			buff->remaining = 0;	/* skip failing sector */			/* buff->ptr       = buff->address; */			/* fake success: */			continue_xfer(buff, fdc_mode, 1);			/*  trace calls are expensive: place them AFTER			 *  the real stuff has been done.			 *  			 */			TRACE(ft_t_noise, "skipping empty segment %d (read), size? %d",			      buff->segment_id, buff->ptr - buff->address);			TRACE_EXIT;		}		if (buff->retry > 0) {			TRACE(ft_t_flow, "this is retry nr %d", buff->retry);		}		switch (cause) {		case no_error:			determine_progress(buff, cause, in[5]);			if (in[2] & 0x40) {				/*  Handle deleted data in header segments.				 *  Skip segment and force read-ahead.				 */				TRACE(ft_t_warn,				      "deleted data in segment %d/%d",				      buff->segment_id,				      FT_SECTOR(buff->sector_offset - 1));				buff->deleted = 1;				buff->remaining = 0;/*abort transfer */				buff->soft_error_map |=						(-1L << buff->sector_offset);				if (buff->segment_id == 0) {					/* stop on next segment */					stop_read_ahead = 1;				}				/* force read-ahead: */				buff->next_segment = 					buff->segment_id + 1;				skip = (FT_SECTORS_PER_SEGMENT - 					buff->sector_offset);			} else {				skip = 0;			}			continue_xfer(buff, fdc_mode, skip);			break;		case no_data_error:			/* Tape started too far ahead of or behind the			 * right sector.  This may also happen in the			 * middle of a segment !			 *			 * Handle no-data as soft error. If next			 * sector fails too, a retry (with needed			 * reposition) will follow.			 */			retry ++;		case id_am_error:		case id_crc_error:		case data_am_error:		case data_crc_error:		case overrun_error:			retry += (buff->soft_error_map != 0 ||				  buff->hard_error_map != 0);			determine_progress(buff, cause, in[5]); #if 1 || defined(TESTING)			if (cause == overrun_error) retry ++;#endif			if (retry) {				skip = find_resume_point(buff);			} else {				skip = buff->sector_offset;			}			/*  Try to resume with next sector on single			 *  errors (let ecc correct it), but retry on			 *  no_data (we'll be past the target when we			 *  get here so we cannot retry) or on			 *  multiple errors (reduce chance on ecc			 *  failure).			 */			/*  cH: 23/02/97: if the last sector in the 			 *  segment was a hard error, then there is 			 *  no sense in a retry. This occasion seldom			 *  occurs but ... @:巢竊@%&

⌨️ 快捷键说明

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