zftape-eof.c 5.9 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
/*
 *   I use these routines just to decide when I have to fake a 
 *   volume-table to preserve compatibility to original ftape.
 */
/*
 *      Copyright (C) 1994-1995 Bas Laarhoven.
 *      
 *      Modified for zftape 1996, 1997 Claus Heine.

 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: /homes/cvs/ftape-stacked/ftape/zftape/zftape-eof.c,v $
 * $Revision: 1.2 $
 * $Date: 1997/10/05 19:19:02 $
 *
 *      This file contains the eof mark handling code
 *      for the QIC-40/80 floppy-tape driver for Linux.
 */

#include <linux/string.h>
#include <linux/errno.h>

#include <linux/zftape.h>

#include "../zftape/zftape-init.h"
#include "../zftape/zftape-rw.h"
#include "../zftape/zftape-eof.h"

/*      Global vars.
 */

/* a copy of the failed sector log from the header segment.
 */
eof_mark_union *zft_eof_map;

/* number of eof marks (entries in bad sector log) on tape.
 */
int zft_nr_eof_marks = -1;


/*      Local vars.
 */

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 zft_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 (__u32) 0 entry.
 */

int zft_ftape_validate_label(char *label)
{
	static char tmp_label[45];
	int result = 0;
	TRACE_FUN(ft_t_any);
	
	memcpy(tmp_label, label, FT_LABEL_SZ);
	tmp_label[FT_LABEL_SZ] = '\0';
	TRACE(ft_t_noise, "tape  label = `%s'", tmp_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);
	}
	TRACE(ft_t_noise, "format version = %d", ftape_fmt_version);
	TRACE_EXIT result;
}

static __u8 * find_end_of_eof_list(__u8 * ptr, __u8 * limit)
{
	while (ptr + 3 < limit) {

		if (get_unaligned((__u32*)ptr)) {
			ptr += sizeof(__u32);
		} else {
			return ptr;
		}
	}
	return NULL;
}

void zft_ftape_extract_file_marks(__u8* address)
{
	int i;
	TRACE_FUN(ft_t_any);
	
	zft_eof_map = NULL;
	if (ft_format_code == fmt_var || ft_format_code == fmt_big) {
		__u8* end;
		__u8* start = ftape_find_end_of_bsm_list(address);

		zft_nr_eof_marks = 0;
		if (start) {
			start += 3; /* skip end of list mark */
			end = find_end_of_eof_list(start, 
						   address + FT_SEGMENT_SIZE);
			if (end && end - start <= FT_FSL_SIZE) {
				zft_nr_eof_marks = ((end - start) / 
						    sizeof(eof_mark_union));
				zft_eof_map = (eof_mark_union *)start;
			} else {
				TRACE(ft_t_err,
				      "EOF Mark List is too long or damaged!");
			}
		} else {
			TRACE(ft_t_err, 
			      "Bad Sector List is too long or damaged !");
		}
	} else {
		zft_eof_map = (eof_mark_union *)&address[FT_FSL];
		zft_nr_eof_marks = GET2(address, FT_FSL_CNT);
	}
	TRACE(ft_t_noise, "number of file marks: %d", zft_nr_eof_marks);
	if (ftape_fmt_version == 1) {
		TRACE(ft_t_info, "swapping version 1 fields");
		/* version 1 format uses swapped sector and segment
		 * fields, correct that !  
		 */
		for (i = 0; i < zft_nr_eof_marks; ++i) {
			__u16 tmp = GET2(&zft_eof_map[i].mark.segment,0);
			PUT2(&zft_eof_map[i].mark.segment, 0, 
			     GET2(&zft_eof_map[i].mark.date,0));
			PUT2(&zft_eof_map[i].mark.date, 0, tmp);
		}
	}
	for (i = 0; i < zft_nr_eof_marks; ++i) {
		TRACE(ft_t_noise, "eof mark: %5d/%2d",
			GET2(&zft_eof_map[i].mark.segment, 0), 
			GET2(&zft_eof_map[i].mark.date,0));
	}
	TRACE_EXIT;
}

void zft_clear_ftape_file_marks(void)
{
	TRACE_FUN(ft_t_flow);
	/*  Clear failed sector log: remove all tape marks. We
	 *  don't use old ftape-style EOF-marks.
	 */
	TRACE(ft_t_info, "Clearing old ftape's eof map");
	memset(zft_eof_map, 0, zft_nr_eof_marks * sizeof(__u32));
	zft_nr_eof_marks = 0;
	PUT2(zft_hseg_buf, FT_FSL_CNT, 0); /* nr of eof-marks */
	zft_header_changed = 1;
	zft_update_label(zft_hseg_buf);
	TRACE_EXIT;
}