static int ftape_new_cartridge(void) { ft_location.track = -1; /* force seek on first access */ ftape_zap_read_buffers(); ftape_zap_write_buffers(); return 0; }
int ftape_new_cartridge(void) { location.track = -1; /* force seek on first access */ first_data_segment = -1; /* unknown */ ftape_zap_read_buffers(); ftape_zap_write_buffers(); ftape_reset_position(); return 0; }
/* 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; }
int ftape_flush_buffers(void) { TRACE_FUN(5, "ftape_flush_buffers"); int result; int pad_count; int data_remaining; static int active = 0; if (active) { TRACE(5, "nested call, abort"); TRACE_EXIT; return 0; } active = 1; TRACEi(5, "entered, ftape_state =", ftape_state); if (ftape_state != writing && !need_flush) { active = 0; TRACE(5, "no need for flush"); TRACE_EXIT; return 0; } data_remaining = buf_pos_wr; buf_pos_wr = 0; /* prevent further writes if this fails */ TRACE(5, "flushing write buffers"); if (last_write_failed) { ftape_zap_write_buffers(); active = 0; TRACE_EXIT; return write_protected ? -EROFS : -EIO; } /* * If there is any data not written to tape yet, append zero's * up to the end of the sector. Then write the segment(s) to tape. */ if (data_remaining > 0) { int written; do { TRACEi(4, "remaining in buffer:", data_remaining); pad_count = sizeof(deblock_buffer) - data_remaining; TRACEi(7, "flush, padding count:", pad_count); memset(deblock_buffer + data_remaining, 0, pad_count); /* pad buffer */ result = _write_segment(ftape_seg_pos, deblock_buffer, 1); if (result < 0) { if (result != -ENOSPC) { last_write_failed = 1; } active = 0; TRACE_EXIT; return result; } written = result; clear_eof_mark_if_set(ftape_seg_pos, written); TRACEi(7, "flush, moved out buffer:", written); if (written > 0) { data_remaining -= written; if (data_remaining > 0) { /* Need another segment for remaining data, move the remainder * to the beginning of the buffer */ memmove(deblock_buffer, deblock_buffer + written, data_remaining); } } ++ftape_seg_pos; } while (data_remaining > 0); /* Data written to last segment == data_remaining + written * value is in range [1..29K]. */ TRACEx2(4, "last write: %d, netto pad-count: %d", data_remaining + written, -data_remaining); if (-1024 < data_remaining && data_remaining <= 0) { /* Last sector of segment was used for data, so put eof mark * in next segment and position at second file mark. */ if (ftape_weof(2, ftape_seg_pos, 1) >= 0) { ++ftape_seg_pos; /* position between file marks */ } } else { /* Put eof mark in previous segment after data and position * at second file mark. */ ftape_weof(2, ftape_seg_pos - 1, 1 + ((SECTOR_SIZE - 1 + result + data_remaining) / SECTOR_SIZE)); } } else { TRACE(7, "deblock_buffer empty"); if (ftape_weof(2, ftape_seg_pos, 1) >= 0) { ++ftape_seg_pos; /* position between file marks */ } start_writing(WRITE_MULTI); } TRACE(7, "waiting"); result = loop_until_writes_done(); if (result < 0) { TRACE(1, "flush buffers failed"); } ftape_state = idle; last_write_failed = 0; need_flush = 0; active = 0; 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; }