📄 ftape-write.c
字号:
/* * Copyright (C) 1993-1995 Bas Laarhoven. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. $Source: /usr/local/cvsroot/AplioTRIO/linux/drivers/char/ftape/ftape-write.c,v $ $Author: vadim $ * $Revision: 1.1.1.1 $ $Date: 1999/11/15 13:41:58 $ $State: Exp $ * * This file contains the writing code * for the QIC-117 floppy-tape driver for Linux. */#include <linux/string.h>#include <linux/errno.h>#include <linux/mm.h>#include <linux/ftape.h>#include <asm/segment.h>#include "tracing.h"#include "ftape-write.h"#include "ftape-read.h"#include "qic117.h"#include "ftape-io.h"#include "ftape-ctl.h"#include "ftape-rw.h"#include "ftape-eof.h"#include "ecc.h"#include "ftape-bsm.h"/* Global vars. *//* Local vars. */static int buf_pos_wr = 0;static int last_write_failed = 0;static int need_flush = 0;#define WRITE_MULTI 0#define WRITE_SINGLE 1void ftape_zap_write_buffers(void){ int i; for (i = 0; i < NR_BUFFERS; ++i) { buffer[i].status = done; } need_flush = 0;}int copy_and_gen_ecc(char *destination, byte * source, unsigned int bad_sector_map){ TRACE_FUN(8, "copy_and_gen_ecc"); int result; struct memory_segment mseg; int bads = count_ones(bad_sector_map); if (bads > 0) { TRACEi(4, "bad sectors in map:", bads); } if (bads + 3 >= SECTORS_PER_SEGMENT) { TRACE(4, "empty segment"); mseg.blocks = 0; /* skip entire segment */ result = 0; /* nothing written */ } else { mseg.blocks = SECTORS_PER_SEGMENT - bads; mseg.data = destination; memcpy(mseg.data, source, (mseg.blocks - 3) * SECTOR_SIZE); result = ecc_set_segment_parity(&mseg); if (result < 0) { TRACE(1, "ecc_set_segment_parity failed"); } else { result = (mseg.blocks - 3) * SECTOR_SIZE; } } TRACE_EXIT; return result;}void prevent_flush(void){ need_flush = 0; ftape_state = idle;}int start_writing(int mode){ TRACE_FUN(5, "start_writing"); int result = 0; buffer_struct *buff = &buffer[head]; int segment_id = buff->segment_id; if (ftape_state == writing && buff->status == waiting) { setup_new_segment(buff, segment_id, 1); if (mode == WRITE_SINGLE) { buffer[head].next_segment = 0; /* stop tape instead of pause */ } calc_next_cluster(buff); /* prepare */ buff->status = writing; if (runner_status == idle) { TRACEi(5, "starting runner for segment", segment_id); result = ftape_start_tape(segment_id, buff->sector_offset); if (result >= 0) { runner_status = running; } } if (result >= 0) { result = setup_fdc_and_dma(buff, FDC_WRITE); /* go */ } ftape_state = writing; } 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;}/* Write as much as fits from buffer to the given segment on tape * and handle retries. * Return the number of bytes written (>= 0), or: * -EIO write failed * -EINTR interrupted by signal * -ENOSPC device full */int _write_segment(unsigned int segment_id, byte * buffer, int flush){ TRACE_FUN(5, "_write_segment"); int retry = 0; int result; history.used |= 2; for (;;) { if (segment_id > ftape_last_segment.id && !flush) { result = -ENOSPC; /* tape full */ break; } result = write_segment(segment_id, buffer, flush); if (result < 0) { if (result == -EAGAIN) { if (++retry > 100) { TRACE(1, "write failed, >100 retries in segment"); result = -EIO; /* give up */ break; } else { TRACEx1(2, "write error, retry %d", retry); } } else { TRACEi(1, "write_segment failed, error:", -result); break; } } else { /* success */ if (result == 0) { /* empty segment */ TRACE(4, "empty segment, nothing written"); } break; } /* 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; } } TRACE_EXIT; return result;}int update_header_segment(unsigned segment, byte * buffer){ TRACE_FUN(5, "update_header_segment"); int result = 0; int status; if (buffer == NULL) { TRACE(5, "no input buffer specified"); buffer = deblock_buffer; result = read_segment(used_header_segment, buffer, &status, 0); if (bad_sector_map_changed) { store_bad_sector_map(buffer); } if (failed_sector_log_changed) { update_failed_sector_log(buffer); } } if (result >= 0 && GET4(buffer, 0) != 0xaa55aa55) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -