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; }
int ftape_abort_operation(void) { TRACE_FUN(5, "ftape_abort_operation"); int result = 0; int i; int status; if (runner_status == running) { TRACE(5, "aborting runner, waiting"); 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 (result == 0) { runner_status = idle; } } if (runner_status != idle) { if (runner_status == do_abort) { TRACE(5, "forcing runner abort"); } TRACE(5, "stopping tape"); result = ftape_command_wait(QIC_STOP_TAPE, timeout.stop, &status); location.known = 0; runner_status = idle; } for (i = 0; i < NR_BUFFERS; ++i) { buffer[i].status = waiting; } head = tail = 0; TRACE_EXIT; return result; }
int loop_until_writes_done(void) { TRACE_FUN(5, "loop_until_writes_done"); int i; int result = 0; /* * Wait until all data is actually written to tape. */ while (ftape_state == writing && buffer[head].status != done) { TRACEx2(7, "tail: %d, head: %d", tail, head); for (i = 0; i < NR_BUFFERS; ++i) { TRACEx3(8, "buffer[ %d] segment_id: %d, status: %d", i, buffer[i].segment_id, buffer[i].status); } result = fdc_interrupt_wait(5 * SECOND); if (result < 0) { TRACE(1, "fdc_interrupt_wait failed"); last_write_failed = 1; break; } if (buffer[head].status == error) { /* Allow escape from loop when signaled ! */ if (current->signal & _DONT_BLOCK) { TRACE(2, "interrupted by signal"); TRACE_EXIT; result = -EINTR; /* is this the right return value ? */ break; } if (buffer[head].hard_error_map != 0) { /* Implement hard write error recovery here */ } buffer[head].status = waiting; /* retry this one */ if (runner_status == aborting) { ftape_dumb_stop(); runner_status = idle; } if (runner_status != idle) { TRACE(1, "unexpected state: runner_status != idle"); result = -EIO; break; } start_writing(WRITE_MULTI); } TRACE(5, "looping until writes done"); result = 0; /* normal exit status */ } 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; }