summaryrefslogtreecommitdiff
path: root/drivers/char/ftape/zftape/zftape-eof.c
blob: dcadcaee9ac1260027adf35195b2d2edfe9332c3 (plain)
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;
}