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

📄 fdc-isr.c

📁 arm平台上的uclinux系统全部源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	} else {		/* current segment completed		 */		unsigned last_segment = buff->segment_id;		int eot = ((last_segment + 1) % segments_per_track) == 0;		int next = buff->next_segment;	/* 0 means stop ! */		buff->bytes = buff->ptr - buff->address;		buff->status = done;		buff = *p_buff = next_buffer(&head);		if (eot) {			/* finished last segment on current track, can't continue			 */			runner_status = logical_eot;			fdc_mode = fdc_idle;		} else if (next > 0) {			/* continue with next segment			 */			if (buff->status == waiting) {				if (write && next != buff->segment_id) {					TRACE(5, "segments out of order, aborting write");					runner_status = do_abort;					fdc_mode = fdc_idle;				} else {					setup_new_segment(&buffer[head], next, 0);					if (stop_read_ahead) {						buff->next_segment = 0;						stop_read_ahead = 0;					}					if (calc_next_cluster(&buffer[head]) == 0 ||					    setup_fdc_and_dma(&buffer[head], fdc_op) != 0) {						TRACEx1(1, "couldn't start %s-ahead", (write) ? "write" : "read");						runner_status = do_abort;						fdc_mode = fdc_idle;					} else {						buff->status = (write) ? writing : reading;	/* keep on going */					}				}			} else {				TRACEx1(5, "all input buffers %s, pausing tape",					(write) ? "empty" : "full");				pause_tape(last_segment, 0, fdc_mode);				runner_status = idle;	/* not quite true until next irq */			}		} else {			/* don't continue with next segment			 */			TRACEx1(5, "no %s allowed, stopping tape",				(write) ? "write next" : "read ahead");			if (random_rw) {				stop_tape(last_segment);			} else {				pause_tape(last_segment, 0, fdc_mode);			}			runner_status = idle;	/* not quite true until next irq */		}	}	TRACE_EXIT;	return;}static voidretry_sector(buffer_struct ** p_buff, error_cause cause, int fdc_mode,	     unsigned skip){	TRACE_FUN(8, "retry_sector");	buffer_struct *buff = *p_buff;	TRACEx1(4, "%s error, will retry",		(fdc_mode == fdc_writing_data) ? "write" : "read");	pause_tape(buff->segment_id, 1, fdc_mode);	runner_status = aborting;	buff->status = error;	buff->skip = skip;	TRACE_EXIT;}static unsignedfind_resume_point(buffer_struct * buff){	TRACE_FUN(8, "find_resume_point");	int i = 0;	unsigned long mask;	unsigned long map;	/*  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) {		TRACEx1(1, "bug: sector_offset = %d", buff->sector_offset);	} else {		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;			}			TRACEx1(4, "at sector %d", SECTOR(i));		} else {			map = buff->hard_error_map & mask;			i = buff->sector_offset - 1;			if (map) {				while ((map & (1 << i)) == 0) {					--i;				}				TRACEx1(4, "after sector %d", SECTOR(i));				++i;	/* first sector after last hard error */			} else {				TRACE(1, "bug: no soft or hard errors");			}		}	}	TRACE_EXIT;	return i;}/*      FDC interrupt service routine. */voidfdc_isr(void){	TRACE_FUN(8, "fdc_isr");	int result;	int status;	error_cause cause = no_error;	byte in[7];	static int isr_active = 0;	int t0;	buffer_struct *buff = &buffer[head];	int skip;	t0 = timestamp();	if (isr_active) {		TRACE(-1, "nested interrupt, not good !");		*fdc.hook = fdc_isr;	/* hook our handler into the fdc code again */		TRACE_EXIT;		return;	}	++isr_active;	sti();			/* enables interrupts again */	status = inb_p(fdc.msr);	if (status & FDC_BUSY) {	/*  Entering Result Phase */		hide_interrupt = 0;		result = fdc_result(in, 7);	/* better get it fast ! */		if (result < 0) {			/*  Entered unknown state...			 */			TRACE(1, "probably fatal error during FDC Result Phase");			TRACE(1, "drive may hang until (power) reset :-(");			/*  what to do next ????			 */		} else {			int i;			char *fdc_mode_txt;			decode_irq_cause(fdc_mode, in, &fdc_mode_txt, &cause);			for (i = 0; i < NR_BUFFERS; ++i) {				TRACEx3(8, "buffer[%d] status: %d, segment_id: %d",					i, buffer[i].status, buffer[i].segment_id);			}			switch (fdc_mode) {			case fdc_reading_data:{					if (cause == no_error) {						TRACEi(5, "reading segment", buff->segment_id);					} else {						TRACEi(4, "error reading segment", buff->segment_id);					}					if (runner_status == aborting || runner_status == do_abort) {						TRACEx1(4, "aborting %s", fdc_mode_txt);						break;					}					if (buff->retry > 0) {						TRACEx1(5, "this is retry nr %d", buff->retry);					}					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.						 */						TRACE(4, "skipping empty segment (read)");						buff->remaining = 0;	/* skip failing sector */						continue_xfer(&buff, no_error, fdc_mode, 1);	/* fake success */					} else {						switch (cause) {						case no_error:{								determine_progress(buff, cause, fdc_reading_data);								if (in[2] & 0x40) {									/*  Handle deleted data in header segments.									 *  Skip segment and force read-ahead.									 */									TRACEx1(2, "deleted data in sector %d",										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_read_ahead = 1;	/* stop on next segment */									}									buff->next_segment = buff->segment_id + 1;	/* force read-ahead */									skip = (SECTORS_PER_SEGMENT - buff->sector_offset);								} else {									skip = 0;								}								continue_xfer(&buff, cause, 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.							 */						case id_am_error:						case id_crc_error:						case data_am_error:						case data_crc_error:						case overrun_error:{								int first_error = (buff->soft_error_map == 0 &&										   buff->hard_error_map == 0);								update_history(cause);								determine_progress(buff, cause, fdc_reading_data);								if (first_error) {									skip = buff->sector_offset;								} else {									skip = find_resume_point(buff);								}								/*  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).								 */								if (first_error && cause != no_data_error) {									continue_xfer(&buff, cause, fdc_mode, skip);								} else {									retry_sector(&buff, cause, fdc_mode, skip);								}								break;							}						default:{								/*  Don't know why this could happen but find out.								 */								TRACE(1, "unexpected error");								determine_progress(buff, cause, fdc_reading_data);								retry_sector(&buff, cause, fdc_mode, 0);								break;							}						}					}					break;				}			case fdc_reading_id:{					if (cause == no_error) {						fdc_cyl = in[3];						fdc_head = in[4];						fdc_sect = in[5];						TRACEx3(6, "id read: C: 0x%02x, H: 0x%02x, R: 0x%02x",							fdc_cyl, fdc_head, fdc_sect);					} else {	/* no valid information, use invalid sector */						fdc_cyl =						    fdc_head =						    fdc_sect = 0;						TRACE(5, "Didn't find valid sector Id");					}					fdc_mode = fdc_idle;					break;				}			case fdc_writing_data:{					if (cause == no_error) {						TRACEi(5, "writing segment", buff->segment_id);					} else {						TRACEi(4, "error writing segment", buff->segment_id);					}					if (runner_status == aborting || runner_status == do_abort) {						TRACEx1(5, "aborting %s", fdc_mode_txt);						break;					}					if (buff->retry > 0) {						TRACEx1(5, "this is retry nr %d", buff->retry);					}					if (buff->bad_sector_map == FAKE_SEGMENT) {						/* This condition occurs when trying to write to a `fake'						 * sector that's not accessible. Doesn't really matter as						 * it isn't used anyway ! Might be located at wrong segment,						 * then we'll fail on the next segment.						 */						TRACE(4, "skipping empty segment (write)");						buff->remaining = 0;	/* skip failing sector */						continue_xfer(&buff, no_error, fdc_mode, 1);	/* fake success */					} else {						switch (cause) {						case no_error:{								determine_progress(buff, cause, fdc_writing_data);								continue_xfer(&buff, cause, fdc_mode, 0);								break;							}						case no_data_error:						case id_am_error:						case id_crc_error:						case data_am_error:						case overrun_error:{								update_history(cause);								determine_progress(buff, cause, fdc_writing_data);								skip = find_resume_point(buff);								retry_sector(&buff, cause, fdc_mode, skip);								break;							}						default:{								if (in[1] & 0x02) {									TRACE(1, "media not writable");								} else {									TRACE(-1, "unforeseen write error");								}								fdc_mode = fdc_idle;								break;							}						}					}					break;				}			default:				TRACEx1(1, "Warning: unexpected irq during: %s",					fdc_mode_txt);				fdc_mode = fdc_idle;				break;			}		}		if (runner_status == do_abort) {			/*      cease operation, remember tape position			 */			TRACE(5, "runner aborting");			runner_status = aborting;			++expected_stray_interrupts;		}	} else { /* !FDC_BUSY  */		/*  clear interrupt, cause should be gotten by issuing		 *  a Sense Interrupt Status command.		 */		if (fdc_mode == fdc_recalibrating || fdc_mode == fdc_seeking) {			if (hide_interrupt) {				int st0;				int pcn;				result = fdc_sense_interrupt_status(&st0, &pcn);				current_cylinder = pcn;				TRACE(5, "handled hidden interrupt");			}			seek_completed = 1;			fdc_mode = fdc_idle;		} else if (!waitqueue_active(&wait_intr)) {			if (expected_stray_interrupts == 0) {				TRACE(2, "unexpected stray interrupt");			} else {				TRACE(5, "expected stray interrupt");				--expected_stray_interrupts;			}		} else {			if (fdc_mode == fdc_reading_data || fdc_mode == fdc_writing_data ||			    fdc_mode == fdc_reading_id) {				byte status = inb_p(fdc.msr);				if (status & FDC_BUSY) {					TRACE(-1, "***** FDC failure, busy too late");				} else {					TRACE(-1, "***** FDC failure, no busy");				}			} else {				TRACE(6, "awaited stray interrupt");			}		}		hide_interrupt = 0;	}	/*    Handle sleep code.	 */	if (!hide_interrupt) {		++interrupt_seen;		if (wait_intr) {			wake_up_interruptible(&wait_intr);		}	} else {		TRACEx1(5, "hiding interrupt while %s", wait_intr ? "waiting" : "active");	}	t0 = timediff(t0, timestamp());	if (t0 >= 1000) {	/* only tell us about long calls */		TRACEx1(7, "isr() duration: %5d usec", t0);	}	*fdc.hook = fdc_isr;	/* hook our handler into the fdc code again */	TRACE_EXIT;	--isr_active;}

⌨️ 快捷键说明

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