patch-2.1.66 linux/drivers/char/ftape/ftape-eof.c
Next file: linux/drivers/char/ftape/ftape-eof.h
Previous file: linux/drivers/char/ftape/ftape-ctl.h
Back to the patch index
Back to the overall index
- Lines: 555
- Date:
Wed Dec 31 16:00:00 1969
- Orig file:
v2.1.65/linux/drivers/char/ftape/ftape-eof.c
- Orig date:
Thu Mar 14 01:53:44 1996
diff -u --recursive --new-file v2.1.65/linux/drivers/char/ftape/ftape-eof.c linux/drivers/char/ftape/ftape-eof.c
@@ -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;
-}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov