📄 ftape-rw.c
字号:
int expected = 0; int count = 1; int short_seek; int target = segment_id - margin; TRACE_FUN(ft_t_flow); if (ft_location.known && !validate(segment_id)) { ftape_sleep(1 * FT_SECOND); ft_failure = 1; TRACE_ABORT(-EIO, ft_t_err, "fatal: head off track (bad hardware?)"); } do { if (!ft_location.known) { TRACE(ft_t_warn, "warning: location not known"); } TRACE(ft_t_noise, "from %d/%d to %d/0 - %d", ft_location.segment, ft_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 (ft_location.segment - target - (min_rewind - 1) < 1) { short_seek = 1; } else { count = ft_location.segment - target - overshoot; short_seek = (count < 1); } if (short_seek) { count = 1; /* do shortest rewind */ expected = ft_location.segment - min_rewind; if (expected/ft_segments_per_track != ft_location.track) { expected = (ft_location.track * ft_segments_per_track); } } else { expected = target; } fast_seek(count, 1); logical_forward(); if (ftape_read_id() < 0 || !ft_location.known || (sigtestsetmask(¤t->pending.signal, _DONT_BLOCK))) { if ((!ftape_tape_running && !ft_location.known) || ++failures > FT_SECTORS_PER_SEGMENT) { TRACE_ABORT(-EIO, ft_t_err, "read_id failed completely"); } FT_SIGNAL_EXIT(_DONT_BLOCK); TRACE_CATCH(ftape_report_drive_status(pstatus),); TRACE(ft_t_noise, "ftape_read_id failed, retry (%d)", failures); continue; } TRACE(ft_t_noise, "ended at %d/%d (%d,%d,%d)", ft_location.segment, ft_location.sector, min_rewind, overshoot, inhibit_correction); if (!inhibit_correction && (ft_location.segment < expected || ft_location.segment > expected + margin)) { int error = expected - ft_location.segment; if (short_seek) { TRACE(ft_t_noise, "adjusting min_rewind from %d to %d", min_rewind, min_rewind + error); min_rewind += error; if (min_rewind < -5) { /* is this right ? FIXME ! */ /* keep sane value */ min_rewind = -5; TRACE(ft_t_noise, "clipped min_rewind to %d", min_rewind); } } else { TRACE(ft_t_noise, "adjusting overshoot from %d to %d", overshoot, overshoot + error); overshoot += error; 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); } } } } while (ft_location.segment > segment_id); if (ft_location.known) { TRACE(ft_t_noise, "current location: %d/%d", ft_location.segment, ft_location.sector); } TRACE_EXIT 0;}static int determine_position(void){ int retry = 0; int status; int result; TRACE_FUN(ft_t_flow); if (!ftape_tape_running) { /* This should only happen if tape is stopped by isr. */ TRACE(ft_t_flow, "waiting for tape stop"); if (ftape_ready_wait(ftape_timeout.pause, &status) < 0) { TRACE(ft_t_flow, "drive still running (fatal)"); ftape_tape_running = 1; /* ? */ } } else { ftape_report_drive_status(&status); } if (status & QIC_STATUS_READY) { /* Drive must be ready to check error state ! */ TRACE(ft_t_flow, "drive is ready"); if (status & QIC_STATUS_ERROR) { unsigned int error; qic117_cmd_t command; /* Report and clear error state, try to continue. */ TRACE(ft_t_flow, "error status set"); ftape_report_error(&error, &command, 1); ftape_ready_wait(ftape_timeout.reset, &status); ftape_tape_running = 0; /* ? */ } if (check_bot_eot(status)) { if (ft_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(ft_t_flow, "start tape from logical bot"); logical_forward(); /* start moving */ } } else { if ((status & QIC_STATUS_READY) == 0) { TRACE(ft_t_noise, "waiting for logical end of track"); result = ftape_ready_wait(ftape_timeout.reset, &status); /* error handling needed ? */ } else { TRACE(ft_t_noise, "tape at logical end of track"); } } } else { TRACE(ft_t_flow, "start tape"); logical_forward(); /* start moving */ ft_location.known = 0; /* not cleared by logical forward ! */ } } /* tape should be moving now, start reading id's */ while (!ft_location.known && retry++ < FT_SECTORS_PER_SEGMENT && (result = ftape_read_id()) < 0) { TRACE(ft_t_flow, "location unknown"); /* exit on signal */ FT_SIGNAL_EXIT(_DONT_BLOCK); /* read-id somehow failed, tape may * have reached end or some other * error happened. */ TRACE(ft_t_flow, "read-id failed"); TRACE_CATCH(ftape_report_drive_status(&status),); TRACE(ft_t_err, "ftape_report_drive_status: 0x%02x", status); if (status & QIC_STATUS_READY) { ftape_tape_running = 0; TRACE(ft_t_noise, "tape stopped for unknown reason! " "status = 0x%02x", status); if (status & QIC_STATUS_ERROR || !check_bot_eot(status)) { /* oops, tape stopped but not at end! */ TRACE_EXIT -EIO; } } } TRACE(ft_t_flow, "tape is positioned at segment %d", ft_location.segment); TRACE_EXIT ft_location.known ? 0 : -EIO;}/* 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){ int track = segment_id / ft_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; TRACE_FUN(ft_t_flow); /* 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. */ ftape_tape_running = 0; TRACE(ft_t_noise, "target segment: %d/%d%s", segment_id, sector_offset, ft_buffer[ft_head]->retry > 0 ? " retry" : ""); if (ft_buffer[ft_head]->retry > 0) { /* this is a retry */ int dist = segment_id - last_segment; if ((int)ft_history.overrun_errors < overrun_count_offset) { overrun_count_offset = ft_history.overrun_errors; } else if (dist < 0 || dist > 50) { overrun_count_offset = ft_history.overrun_errors; } else if ((ft_history.overrun_errors - overrun_count_offset) >= 8) { if (ftape_increase_threshold() >= 0) { --ft_buffer[ft_head]->retry; overrun_count_offset = ft_history.overrun_errors; TRACE(ft_t_warn, "increased threshold because " "of excessive overrun errors"); } else if (!bad_bus_timing && ft_data_rate >= 1000) { ftape_half_data_rate(); --ft_buffer[ft_head]->retry; bad_bus_timing = 1; overrun_count_offset = ft_history.overrun_errors; TRACE(ft_t_warn, "reduced datarate because " "of excessive overrun errors"); } } } last_segment = segment_id; if (ft_location.track != track || (ftape_might_be_off_track && ft_buffer[ft_head]->retry== 0)) { /* current track unknown or not equal to destination */ ftape_ready_wait(ftape_timeout.seek, &status); ftape_seek_head_to_track(track); /* overrun_count_offset = ft_history.overrun_errors; */ } result = -EIO; retry = 0; while (result < 0 && retry++ <= 5 && !ft_failure && !(sigtestsetmask(¤t->pending.signal, _DONT_BLOCK))) { if (retry && start_offset < 5) { start_offset ++; } /* Check if we are able to catch the requested * segment in time. */ if ((ft_location.known || (determine_position() == 0)) && ft_location.segment >= (segment_id - ((ftape_tape_running || ft_location.bot) ? 0 : start_offset))) { /* Too far ahead (in or past target segment). */ if (ftape_tape_running) { if ((result = ftape_stop_tape(&status)) < 0) { TRACE(ft_t_err, "stop tape failed with code %d", result); break; } TRACE(ft_t_noise, "tape stopped"); ftape_tape_running = 0; } TRACE(ft_t_noise, "repositioning"); ++ft_history.rewinds; if (segment_id % ft_segments_per_track < start_offset){ TRACE(ft_t_noise, "end of track condition\n" KERN_INFO "segment_id : %d\n" KERN_INFO "ft_segments_per_track: %d\n" KERN_INFO "start_offset : %d", segment_id, ft_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( (ft_location.track & 1) ? QIC_PHYSICAL_FORWARD : QIC_PHYSICAL_REVERSE, ftape_timeout.rewind, &status); check_bot_eot(status); /* update location */ } else { result= skip_reverse(segment_id - start_offset, &status); } } if (!ft_location.known) { TRACE(ft_t_bug, "panic: location not known"); result = -EIO; continue; /* while() will check for failure */ } TRACE(ft_t_noise, "current segment: %d/%d", ft_location.segment, ft_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 (ft_location.segment < (segment_id - ((ftape_tape_running || ft_location.bot) ? 0 : start_offset))) { if (sector_offset > 0) { result = seek_forward(segment_id, retry <= 3); } else { result = seek_forward(segment_id - 1, retry <= 3); } } if (result == 0 && ft_location.segment != (segment_id - (sector_offset > 0 ? 0 : 1))) { result = -EIO; } } if (result < 0) { TRACE(ft_t_err, "failed to reposition"); } else { ft_runner_status = running; } TRACE_EXIT result;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -