int ftape_abort_operation(void) { int result = 0; int status; TRACE_FUN(ft_t_flow); if (ft_runner_status == running) { TRACE(ft_t_noise, "aborting runner, waiting"); ft_runner_status = do_abort; /* set timeout so that the tape will run to logical EOT * if we missed the last sector and there are no queue pulses. */ result = ftape_dumb_stop(); } if (ft_runner_status != idle) { if (ft_runner_status == do_abort) { TRACE(ft_t_noise, "forcing runner abort"); } TRACE(ft_t_noise, "stopping tape"); result = ftape_stop_tape(&status); ft_location.known = 0; ft_runner_status = idle; } ftape_reset_buffer(); ftape_zap_read_buffers(); ftape_set_state(idle); TRACE_EXIT result; }
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; }
int ftape_set_nr_buffers(int cnt) { int delta = cnt - ft_nr_buffers; TRACE_FUN(ft_t_flow); if (delta > 0) { while (delta--) { if (add_one_buffer() < 0) { TRACE_EXIT -ENOMEM; } } } else if (delta < 0) { while (delta++) { del_one_buffer(); } } ftape_zap_read_buffers(); TRACE_EXIT 0; }
static void zft_init_driver(void) { TRACE_FUN(ft_t_flow); zft_resid = zft_header_read = zft_old_ftape = zft_offline = zft_write_protected = going_offline = zft_mt_compression = zft_header_changed = zft_volume_table_changed = zft_written_segments = 0; zft_blk_sz = CONFIG_ZFT_DFLT_BLK_SZ; zft_reset_position(&zft_pos); /* does most of the stuff */ ftape_zap_read_buffers(); ftape_set_state(idle); TRACE_EXIT; }
/* 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; }