diff options
Diffstat (limited to 'drivers/char/ftape/ftape-eof.c')
-rw-r--r-- | drivers/char/ftape/ftape-eof.c | 554 |
1 files changed, 0 insertions, 554 deletions
diff --git a/drivers/char/ftape/ftape-eof.c b/drivers/char/ftape/ftape-eof.c deleted file mode 100644 index 75c4cbd76..000000000 --- a/drivers/char/ftape/ftape-eof.c +++ /dev/null @@ -1,554 +0,0 @@ - -/* - * Copyright (C) 1994-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: /home/bas/distr/ftape-2.03b/RCS/ftape-eof.c,v $ - $Author: bas $ - * - $Revision: 1.21 $ - $Date: 1995/05/27 08:54:21 $ - $State: Beta $ - * - * This file contains the eof mark handling code - * for the QIC-40/80 floppy-tape driver for Linux. - */ - -#include <linux/ftape.h> -#include <linux/string.h> -#include <linux/errno.h> - -#include "tracing.h" -#include "ftape-eof.h" -#include "ftape-write.h" -#include "ftape-read.h" -#include "ftape-rw.h" -#include "ftape-ctl.h" -#include "ftape-bsm.h" - -/* Global vars. - */ -int failed_sector_log_changed = 0; -int eof_mark = 0; - -/* Local vars. - */ -static struct failed_sector_entry { - unsigned short segment; - unsigned short sector; -} *eof_mark_ptr; - -typedef union { - struct failed_sector_entry mark; - unsigned long entry; -} eof_mark_union; - -/* a copy of the failed sector log from the header segment. - */ -static eof_mark_union eof_map[(2048 - 256) / 4]; - -/* index into eof_map table pointing to last found eof mark. - */ -static int eof_index; - -/* number of eof marks (entries in bad sector log) on tape. - */ -static int nr_of_eof_marks = -1; - -static char linux_tape_label[] = "Linux raw format V"; -enum { - min_fmt_version = 1, max_fmt_version = 2 -}; -static unsigned ftape_fmt_version = 0; - - -/* Ftape (mis)uses the bad sector log to record end-of-file marks. - * Initially (when the tape is erased) all entries in the bad sector - * log are added to the tape's bad sector map. The bad sector log - * then is cleared. - * - * The bad sector log normally contains entries of the form: - * even 16-bit word: segment number of bad sector - * odd 16-bit word: encoded date - * There can be a total of 448 entries (1792 bytes). - * - * My guess is that no program is using this bad sector log (the - * format seems useless as there is no indication of the bad sector - * itself, only the segment) - * However, if any program does use the bad sector log, the format - * used by ftape will let the program think there are some bad sectors - * and no harm is done. - * - * The eof mark entries that ftape stores in the bad sector log: - * even 16-bit word: segment number of eof mark - * odd 16-bit word: sector number of eof mark [1..32] - * - * The eof_map as maintained is a sorted list of eof mark entries. - * - * - * The tape name field in the header segments is used to store a - * linux tape identification string and a version number. - * This way the tape can be recognized as a Linux raw format - * tape when using tools under other OS's. - * - * 'Wide' QIC tapes (format code 4) don't have a failed sector list - * anymore. That space is used for the (longer) bad sector map that - * now is a variable length list too. - * We now store our end-of-file marker list after the bad-sector-map - * on tape. The list is delimited by a (long) 0 entry. - */ - -int ftape_validate_label(char *label) -{ - TRACE_FUN(8, "ftape_validate_label"); - int result = 0; - - TRACEx1(4, "tape label = `%s'", label); - ftape_fmt_version = 0; - if (memcmp(label, linux_tape_label, strlen(linux_tape_label)) == 0) { - int pos = strlen(linux_tape_label); - while (label[pos] >= '0' && label[pos] <= '9') { - ftape_fmt_version *= 10; - ftape_fmt_version = label[pos++] - '0'; - } - result = (ftape_fmt_version >= min_fmt_version && - ftape_fmt_version <= max_fmt_version); - } - TRACEx1(4, "format version = %d", ftape_fmt_version); - TRACE_EXIT; - return result; -} - -static byte * - find_end_of_eof_list(byte * ptr, byte * limit) -{ - while (ptr + 3 < limit) { - if (*(unsigned long *) ptr) { - ++(unsigned long *) ptr; - } else { - return ptr; - } - } - return NULL; -} - -void reset_eof_list(void) -{ - TRACE_FUN(8, "reset_eof_list"); - - eof_mark_ptr = &eof_map[0].mark; - eof_index = 0; - eof_mark = 0; - TRACE_EXIT; -} - -/* Test if `segment' has an eof mark set (optimized for sequential access). - * return 0 if not eof mark or sector number (> 0) if eof mark set. - */ -int check_for_eof(unsigned segment) -{ - TRACE_FUN(8, "check_for_eof"); - static unsigned last_reference = INT_MAX; - int result; - - if (segment < last_reference) { - reset_eof_list(); - } - last_reference = segment; - while (eof_index < nr_of_eof_marks && segment > eof_mark_ptr->segment) { - ++eof_mark_ptr; - ++eof_index; - } - if (eof_index < nr_of_eof_marks && segment == eof_mark_ptr->segment) { - TRACEx3(5, "hit mark %d/%d at index %d", - eof_map[eof_index].mark.segment, eof_map[eof_index].mark.sector, - eof_index); - if (eof_mark_ptr->sector >= SECTORS_PER_SEGMENT) { - TRACEx2(-1, "Bad file mark detected: %d/%d", - eof_mark_ptr->segment, eof_mark_ptr->sector); - result = 0; /* return bogus (but valid) value */ - } else { - result = eof_mark_ptr->sector; - } - } else { - result = 0; - } - TRACE_EXIT; - return result; -} - -void clear_eof_mark_if_set(unsigned segment, unsigned byte_count) -{ - TRACE_FUN(5, "clear_eof_mark_if_set"); - if (ftape_fmt_version != 0 && - check_for_eof(segment) > 0 && - byte_count >= eof_mark_ptr->sector * SECTOR_SIZE) { - TRACEx3(5, "clearing mark %d/%d at index %d", - eof_mark_ptr->segment, eof_mark_ptr->sector, eof_index); - memmove(&eof_map[eof_index], &eof_map[eof_index + 1], - (nr_of_eof_marks - eof_index) * sizeof(*eof_map)); - --nr_of_eof_marks; - failed_sector_log_changed = 1; - } - TRACE_EXIT; -} - -void put_file_mark_in_map(unsigned segment, unsigned sector) -{ - TRACE_FUN(8, "put_file_mark_in_map"); - eof_mark_union new; - int index; - eof_mark_union *ptr; - - if (ftape_fmt_version != 0) { - new.mark.segment = segment; - new.mark.sector = sector; - for (index = 0, ptr = &eof_map[0]; - index < nr_of_eof_marks && ptr->mark.segment < segment; - ++index, ++ptr) { - } - if (index < nr_of_eof_marks) { - if (ptr->mark.segment == segment) { - /* overwrite */ - if (ptr->mark.sector == sector) { - TRACEx2(5, "mark %d/%d already exists", - new.mark.segment, new.mark.sector); - } else { - TRACEx5(5, "overwriting %d/%d at index %d with %d/%d", - ptr->mark.segment, ptr->mark.sector, index, - new.mark.segment, new.mark.sector); - ptr->entry = new.entry; - failed_sector_log_changed = 1; - } - } else { - /* insert */ - TRACEx5(5, "inserting %d/%d at index %d before %d/%d", - new.mark.segment, new.mark.sector, index, - ptr->mark.segment, ptr->mark.sector); - memmove(ptr + 1, ptr, (nr_of_eof_marks - index) * sizeof(*eof_map)); - ptr->entry = new.entry; - ++nr_of_eof_marks; - failed_sector_log_changed = 1; - } - } else { - /* append */ - TRACEx3(5, "appending %d/%d at index %d", - new.mark.segment, new.mark.sector, index); - ptr->entry = new.entry; - ++nr_of_eof_marks; - failed_sector_log_changed = 1; - } - } - TRACE_EXIT; -} - -/* Write count file marks to tape starting at first non-bad - * sector following the given segment and sector. - * sector = base 1 ! - */ -int ftape_weof(unsigned count, unsigned segment, unsigned sector) -{ - TRACE_FUN(5, "ftape_weof"); - int result = 0; - unsigned long mask = get_bad_sector_entry(segment); - unsigned sector_nr = 0; - - if (ftape_fmt_version != 0) { - if (sector < 1 || sector > 29 || - segment + count >= ftape_last_segment.id) { - TRACEx3(5, "parameter out of range: %d, %d, %d", count, segment, sector); - result = -EIO; - } else { - while (count-- > 0) { - do { /* count logical sectors */ - do { /* skip until good sector */ - while (mask & 1) { /* skip bad sectors */ - ++sector_nr; - mask >>= 1; - } - if (sector_nr >= 29) { - if (++segment >= ftape_last_segment.id) { - TRACEx1(5, "segment out of range: %d", segment); - result = -EIO; - break; - } - mask = get_bad_sector_entry(segment); - sector_nr = 0; - } - } while (mask & 1); - ++sector_nr; /* point to good sector */ - mask >>= 1; - } while (--sector); - if (result >= 0) { - TRACEx2(5, "writing filemark %d/%d", segment, sector_nr); - put_file_mark_in_map(segment, sector_nr); - ++segment; /* next segment */ - sector_nr = 0; - sector = 1; /* first sector */ - } - } - } - } else { - result = -EPERM; - } - TRACE_EXIT; - return result; -} - -int ftape_erase(void) -{ - TRACE_FUN(5, "ftape_erase"); - int result = 0; - int i; - unsigned long now = 0; - byte *buffer = deblock_buffer; - - if (write_protected) { - result = -EROFS; - } else { - result = read_header_segment(buffer); - if (result >= 0) { - /* Copy entries from bad-sector-log into bad-sector-map - */ - TRACEx1(5, "old label: `%s'", (char *) (buffer + 30)); - if (!ftape_validate_label((char *) &buffer[30])) { - TRACE(5, "invalid label, overwriting with new"); - memset(buffer + 30, 0, 44); - memcpy(buffer + 30, linux_tape_label, strlen(linux_tape_label)); - buffer[30 + strlen(linux_tape_label)] = '2'; - TRACEx1(5, "new label: `%s'", (char *) (buffer + 30)); - PUT4(buffer, 74, now); - if (format_code != 4) { - for (i = 0; i < nr_of_eof_marks; ++i) { - unsigned failing_segment = eof_map[i].mark.segment; - - if (!valid_segment_no(failing_segment)) { - TRACEi(4, "bad entry in failed sector log:", failing_segment); - } else { - put_bad_sector_entry(failing_segment, EMPTY_SEGMENT); - TRACEx2(4, "moved entry %d from failed sector log (%d)", - i, failing_segment); - } - } - } - } - /* Clear failed sector log: remove all tape marks - */ - failed_sector_log_changed = 1; - memset(eof_map, 0, sizeof(eof_map)); - nr_of_eof_marks = 0; - ftape_fmt_version = max_fmt_version; -#if 0 - fix_tape(buffer); /* see ftape-bsm.c ! */ -#endif - result = ftape_update_header_segments(buffer, 1); - prevent_flush(); /* prevent flush_buffers writing file marks */ - reset_eof_list(); - } - } - TRACE_EXIT; - return result; -} - -void extract_file_marks(byte * address) -{ - TRACE_FUN(8, "extract_file_marks"); - int i; - - if (format_code == 4) { - byte *end; - byte *start = find_end_of_bsm_list(address + 256, - address + 29 * SECTOR_SIZE); - - memset(eof_map, 0, sizeof(eof_map)); - nr_of_eof_marks = 0; - if (start) { - start += 3; /* skip end of list mark */ - end = find_end_of_eof_list(start, address + 29 * SECTOR_SIZE); - if (end && end - start <= sizeof(eof_map)) { - nr_of_eof_marks = (end - start) / sizeof(unsigned long); - memcpy(eof_map, start, end - start); - } else { - TRACE(1, "File Mark List is too long or damaged !"); - } - } else { - TRACE(1, "Bad Sector List is too long or damaged !"); - } - } else { - memcpy(eof_map, address + 256, sizeof(eof_map)); - nr_of_eof_marks = GET2(address, 144); - } - TRACEi(4, "number of file marks:", nr_of_eof_marks); - if (ftape_fmt_version == 1) { - TRACE(-1, "swapping version 1 fields"); - /* version 1 format uses swapped sector and segment fields, correct that ! - */ - for (i = 0; i < nr_of_eof_marks; ++i) { - unsigned short tmp = eof_map[i].mark.segment; - eof_map[i].mark.segment = eof_map[i].mark.sector; - eof_map[i].mark.sector = tmp; - } - } - for (i = 0; i < nr_of_eof_marks; ++i) { - TRACEx2(4, "eof mark: %5d/%2d", - eof_map[i].mark.segment, eof_map[i].mark.sector); - } - reset_eof_list(); - TRACE_EXIT; -} - -int update_failed_sector_log(byte * buffer) -{ - TRACE_FUN(8, "update_failed_sector_log"); - - if (ftape_fmt_version != 0 && failed_sector_log_changed) { - if (ftape_fmt_version == 1) { - TRACE(-1, "upgrading version 1 format to version 2"); - /* version 1 will be upgraded to version 2 when written. - */ - buffer[30 + strlen(linux_tape_label)] = '2'; - ftape_fmt_version = 2; - TRACEx1(-1, "new tape label = \"%s\"", &buffer[30]); - } - if (format_code == 4) { - byte *dest = find_end_of_bsm_list(buffer + 256, - buffer + 29 * SECTOR_SIZE) + 3; - - if (dest) { - TRACEx2(4, "eof_map at byte offset %6d, size %d", - dest - buffer - 256, nr_of_eof_marks * sizeof(unsigned long)); - memcpy(dest, eof_map, nr_of_eof_marks * sizeof(unsigned long)); - PUT4(dest, nr_of_eof_marks * sizeof(unsigned long), 0); - } - } else { - memcpy(buffer + 256, eof_map, sizeof(eof_map)); - PUT2(buffer, 144, nr_of_eof_marks); - } - failed_sector_log_changed = 0; - return 1; - } - TRACE_EXIT; - return 0; -} - -int ftape_seek_eom(void) -{ - TRACE_FUN(5, "ftape_seek_eom"); - int result = 0; - unsigned eom; - - if (first_data_segment == -1) { - result = read_header_segment(deblock_buffer); - } - if (result >= 0 && ftape_fmt_version != 0) { - eom = first_data_segment; - eof_index = 0; - eof_mark_ptr = &eof_map[0].mark; - /* If fresh tape, count should be zero but we don't - * want to worry about the case it's one. - */ - for (eof_index = 1, eof_mark_ptr = &eof_map[1].mark; - eof_index < nr_of_eof_marks; ++eof_index, ++eof_mark_ptr) { - /* The eom is recorded as two eof marks in succeeding segments - * where the second one is always at segment number 1. - */ - if (eof_mark_ptr->sector == 1) { - if (eof_mark_ptr->segment == (eof_mark_ptr - 1)->segment + 1) { - eom = eof_mark_ptr->segment; - break; - } - } - } - ftape_seg_pos = eom; - TRACEx1(5, "eom found at segment %d", eom); - } else { - TRACE(5, "Couldn't get eof mark table"); - result = -EIO; - } - TRACE_EXIT; - return result; -} - -int ftape_seek_eof(unsigned count) -{ - TRACE_FUN(5, "ftape_seek_eof"); - int result = 0; - enum { - not = 0, begin, end - } bad_seek = not; - - if (first_data_segment == -1) { - result = read_header_segment(deblock_buffer); - } - TRACEx1(5, "tape positioned at segment %d", ftape_seg_pos); - if (ftape_fmt_version == 0) { - result = -1; - } - if (result >= 0 && count != 0) { - for (eof_index = 0; eof_index <= nr_of_eof_marks; ++eof_index) { - if (eof_index == nr_of_eof_marks || /* start seeking after last mark */ - ftape_seg_pos <= eof_map[eof_index].mark.segment) { - eof_index += count; - if (eof_index < 1) { /* begin of tape */ - ftape_seg_pos = first_data_segment; - if (eof_index < 0) { /* `before' begin of tape */ - eof_index = 0; - bad_seek = begin; - } - } else if (eof_index >= nr_of_eof_marks) { /* `after' end of tape */ - ftape_seg_pos = segments_per_track * tracks_per_tape; - if (eof_index > nr_of_eof_marks) { - eof_index = nr_of_eof_marks; - bad_seek = end; - } - } else { /* after requested file mark */ - ftape_seg_pos = eof_map[eof_index - 1].mark.segment + 1; - } - eof_mark_ptr = &eof_map[eof_index].mark; - break; - } - } - } - if (result < 0) { - TRACE(5, "Couldn't get eof mark table"); - result = -EIO; - } else if (bad_seek != not) { - TRACEx1(1, "seek reached %s of tape", - (bad_seek == begin) ? "begin" : "end"); - result = -EIO; - } else { - TRACEx1(5, "tape repositioned to segment %d", ftape_seg_pos); - } - TRACE_EXIT; - return result; -} - -int ftape_file_no(daddr_t * f_no, daddr_t * b_no) -{ - TRACE_FUN(5, "ftape_file_no"); - int result = 0; - int i; - - *f_no = eof_index; - *b_no = ftape_seg_pos; - TRACEi(4, "number of file marks:", nr_of_eof_marks); - for (i = 0; i < nr_of_eof_marks; ++i) { - TRACEx2(4, "eof mark: %5d/%2d", - eof_map[i].mark.segment, eof_map[i].mark.sector); - } - TRACE_EXIT; - return result; -} |