int ftape_update_header_segments(byte * buffer, int update) { TRACE_FUN(5, "ftape_update_header_segments"); int result = 0; int dummy; int header_changed = 1; if (ftape_state == writing) { result = loop_until_writes_done(); } if (read_only) { result = 0; /* exit and fake success */ TRACE(4, "Tape set read-only: no update"); } else if (result >= 0) { result = ftape_abort_operation(); if (result >= 0) { if (buffer == NULL) { if (bad_sector_map_changed || failed_sector_log_changed) { ftape_seek_to_bot(); /* prevents extra rewind */ buffer = deblock_buffer; result = read_segment(used_header_segment, buffer, &dummy, 0); if (result < 0) { TRACE_EXIT; return result; } } header_changed = 0; } if (update) { if (bad_sector_map_changed) { store_bad_sector_map(buffer); header_changed = 1; } if (failed_sector_log_changed) { update_failed_sector_log(buffer); header_changed = 1; } } if (header_changed) { ftape_seek_to_bot(); /* prevents extra rewind */ result = ftape_write_header_segments(buffer); } } } TRACE_EXIT; return result; }
int zft_def_idle_state(void) { int result = 0; TRACE_FUN(ft_t_flow); if (!zft_header_read) { result = zft_read_header_segments(); } else if ((result = zft_flush_buffers()) >= 0 && zft_qic_mode) { /* don't move past eof */ (void)zft_close_volume(&zft_pos); } if (ftape_abort_operation() < 0) { TRACE(ft_t_warn, "ftape_abort_operation() failed"); result = -EIO; } /* clear remaining read buffers */ zft_zap_read_buffers(); zft_io_state = zft_idle; TRACE_EXIT result; }
/* RELEASE routine called by kernel-interface code */ int _ftape_close(void) { TRACE_FUN(8, "_ftape_close"); int result = 0; int last_segment = 0; if (!ftape_offline) { result = ftape_flush_buffers(); last_segment = ftape_seg_pos - 1; if (!(ftape_unit & FTAPE_NO_REWIND)) { if (result >= 0) { result = ftape_update_header_segments(NULL, 1); if (result < 0) { TRACE(1, "error: update of header segments failed"); } } else { TRACE(1, "error: unable to update header segments"); } } ftape_abort_operation(); if (!(ftape_unit & FTAPE_NO_REWIND)) { if (!no_tape) { TRACE(5, "rewinding tape"); result = ftape_seek_to_bot(); } ftape_reset_position(); ftape_zap_read_buffers(); ftape_zap_write_buffers(); } } ftape_detach_drive(); fdc_uninit(); if (history.used) { TRACE(3, "== Non-fatal errors this run: =="); TRACE(3, "fdc isr statistics:"); TRACEi(3, " id_am_errors :", history.id_am_errors); TRACEi(3, " id_crc_errors :", history.id_crc_errors); TRACEi(3, " data_am_errors :", history.data_am_errors); TRACEi(3, " data_crc_errors :", history.data_crc_errors); TRACEi(3, " overrun_errors :", history.overrun_errors); TRACEi(3, " no_data_errors :", history.no_data_errors); TRACEi(3, " retries :", history.retries); if (history.used & 1) { TRACE(3, "ecc statistics:"); TRACEi(3, " crc_errors :", history.crc_errors); TRACEi(3, " crc_failures :", history.crc_failures); TRACEi(3, " ecc_failures :", history.ecc_failures); TRACEi(3, " sectors corrected:", history.corrected); } TRACEx2(3, "media defects : %d%s", history.defects, history.defects ? " !!!" : ""); TRACEi(3, "repositions :", history.rewinds); TRACEi(3, "last segment :", last_segment); } if (going_offline) { going_offline = 0; ftape_offline = 1; } TRACE_EXIT; return result; }
/* Write given segment from buffer at address onto tape. */ int write_segment(unsigned segment_id, byte * address, int flushing) { TRACE_FUN(5, "write_segment"); int result = 0; int bytes_written = 0; TRACEi(5, "segment_id =", segment_id); if (ftape_state != writing) { if (ftape_state == reading) { TRACE(5, "calling ftape_abort_operation"); result = ftape_abort_operation(); if (result < 0) { TRACE(1, "ftape_abort_operation failed"); } } ftape_zap_read_buffers(); ftape_zap_write_buffers(); ftape_state = writing; } /* if all buffers full we'll have to wait... */ wait_segment(writing); if (buffer[tail].status == error) { /* setup for a retry */ buffer[tail].status = waiting; bytes_written = -EAGAIN; /* force retry */ if (buffer[tail].hard_error_map != 0) { TRACEx1(1, "warning: %d hard error(s) in written segment", count_ones(buffer[tail].hard_error_map)); TRACEx1(4, "hard_error_map = 0x%08lx", buffer[tail].hard_error_map); /* Implement hard write error recovery here */ } } else if (buffer[tail].status == done) { history.defects += count_ones(buffer[tail].hard_error_map); } else { TRACE(1, "wait for empty segment failed"); result = -EIO; } /* If just passed last segment on tape: wait for BOT or EOT mark. */ if (result >= 0 && runner_status == logical_eot) { int status; result = ftape_ready_wait(timeout.seek, &status); if (result < 0 || (status & (QIC_STATUS_AT_BOT | QIC_STATUS_AT_EOT)) == 0) { TRACE(1, "eot/bot not reached"); } else { runner_status = end_of_tape; } } /* should runner stop ? */ if (result >= 0 && (runner_status == aborting || runner_status == buffer_underrun || runner_status == end_of_tape)) { if (runner_status != end_of_tape) { result = ftape_dumb_stop(); } if (result >= 0) { if (runner_status == aborting) { if (buffer[head].status == writing) { buffer[head].status = done; /* ????? */ } } runner_status = idle; /* aborted ? */ } } /* Don't start tape if runner idle and segment empty. */ if (result >= 0 && !(runner_status == idle && get_bad_sector_entry(segment_id) == EMPTY_SEGMENT)) { if (buffer[tail].status == done) { /* now at least one buffer is empty, fill it with our data. * skip bad sectors and generate ecc. * copy_and_gen_ecc return nr of bytes written, * range 0..29 Kb inclusive ! */ result = copy_and_gen_ecc(buffer[tail].address, address, get_bad_sector_entry(segment_id)); if (result >= 0) { bytes_written = result; buffer[tail].segment_id = segment_id; buffer[tail].status = waiting; next_buffer(&tail); } } /* Start tape only if all buffers full or flush mode. * This will give higher probability of streaming. */ if (result >= 0 && runner_status != running && ((head == tail && buffer[tail].status == waiting) || flushing)) { result = start_writing(WRITE_MULTI); } } TRACE_EXIT; return (result < 0) ? result : bytes_written; }