File: /usr/src/linux/drivers/char/ftape/zftape/zftape-eof.c

1     /*
2      *   I use these routines just to decide when I have to fake a 
3      *   volume-table to preserve compatability to original ftape.
4      */
5     /*
6      *      Copyright (C) 1994-1995 Bas Laarhoven.
7      *      
8      *      Modified for zftape 1996, 1997 Claus Heine.
9     
10      This program is free software; you can redistribute it and/or modify
11      it under the terms of the GNU General Public License as published by
12      the Free Software Foundation; either version 2, or (at your option)
13      any later version.
14     
15      This program is distributed in the hope that it will be useful,
16      but WITHOUT ANY WARRANTY; without even the implied warranty of
17      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18      GNU General Public License for more details.
19     
20      You should have received a copy of the GNU General Public License
21      along with this program; see the file COPYING.  If not, write to
22      the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23     
24      * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-eof.c,v $
25      * $Revision: 1.2 $
26      * $Date: 1997/10/05 19:19:02 $
27      *
28      *      This file contains the eof mark handling code
29      *      for the QIC-40/80 floppy-tape driver for Linux.
30      */
31     
32     #include <linux/string.h>
33     #include <linux/errno.h>
34     
35     #include <linux/zftape.h>
36     
37     #include "../zftape/zftape-init.h"
38     #include "../zftape/zftape-rw.h"
39     #include "../zftape/zftape-eof.h"
40     
41     /*      Global vars.
42      */
43     
44     /* a copy of the failed sector log from the header segment.
45      */
46     eof_mark_union *zft_eof_map;
47     
48     /* number of eof marks (entries in bad sector log) on tape.
49      */
50     int zft_nr_eof_marks = -1;
51     
52     
53     /*      Local vars.
54      */
55     
56     static char linux_tape_label[] = "Linux raw format V";
57     enum { 
58     	min_fmt_version = 1, max_fmt_version = 2 
59     };
60     static unsigned ftape_fmt_version = 0;
61     
62     
63     /* Ftape (mis)uses the bad sector log to record end-of-file marks.
64      * Initially (when the tape is erased) all entries in the bad sector
65      * log are added to the tape's bad sector map. The bad sector log then
66      * is cleared.
67      *
68      * The bad sector log normally contains entries of the form: 
69      * even 16-bit word: segment number of bad sector 
70      * odd 16-bit word: encoded date
71      * There can be a total of 448 entries (1792 bytes).
72      *
73      * My guess is that no program is using this bad sector log (the *
74      * format seems useless as there is no indication of the bad sector
75      * itself, only the segment) However, if any program does use the bad
76      * sector log, the format used by ftape will let the program think
77      * there are some bad sectors and no harm is done.
78      *  
79      * The eof mark entries that ftape stores in the bad sector log: even
80      * 16-bit word: segment number of eof mark odd 16-bit word: sector
81      * number of eof mark [1..32]
82      *  
83      * The zft_eof_map as maintained is a sorted list of eof mark entries.
84      *
85      *
86      * The tape name field in the header segments is used to store a linux
87      * tape identification string and a version number.  This way the tape
88      * can be recognized as a Linux raw format tape when using tools under
89      * other OS's.
90      *
91      * 'Wide' QIC tapes (format code 4) don't have a failed sector list
92      * anymore. That space is used for the (longer) bad sector map that
93      * now is a variable length list too.  We now store our end-of-file
94      * marker list after the bad-sector-map on tape. The list is delimited
95      * by a (__u32) 0 entry.
96      */
97     
98     int zft_ftape_validate_label(char *label)
99     {
100     	static char tmp_label[45];
101     	int result = 0;
102     	TRACE_FUN(ft_t_any);
103     	
104     	memcpy(tmp_label, label, FT_LABEL_SZ);
105     	tmp_label[FT_LABEL_SZ] = '\0';
106     	TRACE(ft_t_noise, "tape  label = `%s'", tmp_label);
107     	ftape_fmt_version = 0;
108     	if (memcmp(label, linux_tape_label, strlen(linux_tape_label)) == 0) {
109     		int pos = strlen(linux_tape_label);
110     		while (label[pos] >= '0' && label[pos] <= '9') {
111     			ftape_fmt_version *= 10;
112     			ftape_fmt_version = label[ pos++] - '0';
113     		}
114     		result = (ftape_fmt_version >= min_fmt_version &&
115     			  ftape_fmt_version <= max_fmt_version);
116     	}
117     	TRACE(ft_t_noise, "format version = %d", ftape_fmt_version);
118     	TRACE_EXIT result;
119     }
120     
121     static __u8 * find_end_of_eof_list(__u8 * ptr, __u8 * limit)
122     {
123     	while (ptr + 3 < limit) {
124     
125     		if (get_unaligned((__u32*)ptr)) {
126     			++(__u32*)ptr;
127     		} else {
128     			return ptr;
129     		}
130     	}
131     	return NULL;
132     }
133     
134     void zft_ftape_extract_file_marks(__u8* address)
135     {
136     	int i;
137     	TRACE_FUN(ft_t_any);
138     	
139     	zft_eof_map = NULL;
140     	if (ft_format_code == fmt_var || ft_format_code == fmt_big) {
141     		__u8* end;
142     		__u8* start = ftape_find_end_of_bsm_list(address);
143     
144     		zft_nr_eof_marks = 0;
145     		if (start) {
146     			start += 3; /* skip end of list mark */
147     			end = find_end_of_eof_list(start, 
148     						   address + FT_SEGMENT_SIZE);
149     			if (end && end - start <= FT_FSL_SIZE) {
150     				zft_nr_eof_marks = ((end - start) / 
151     						    sizeof(eof_mark_union));
152     				zft_eof_map = (eof_mark_union *)start;
153     			} else {
154     				TRACE(ft_t_err,
155     				      "EOF Mark List is too long or damaged!");
156     			}
157     		} else {
158     			TRACE(ft_t_err, 
159     			      "Bad Sector List is too long or damaged !");
160     		}
161     	} else {
162     		zft_eof_map = (eof_mark_union *)&address[FT_FSL];
163     		zft_nr_eof_marks = GET2(address, FT_FSL_CNT);
164     	}
165     	TRACE(ft_t_noise, "number of file marks: %d", zft_nr_eof_marks);
166     	if (ftape_fmt_version == 1) {
167     		TRACE(ft_t_info, "swapping version 1 fields");
168     		/* version 1 format uses swapped sector and segment
169     		 * fields, correct that !  
170     		 */
171     		for (i = 0; i < zft_nr_eof_marks; ++i) {
172     			__u16 tmp = GET2(&zft_eof_map[i].mark.segment,0);
173     			PUT2(&zft_eof_map[i].mark.segment, 0, 
174     			     GET2(&zft_eof_map[i].mark.date,0));
175     			PUT2(&zft_eof_map[i].mark.date, 0, tmp);
176     		}
177     	}
178     	for (i = 0; i < zft_nr_eof_marks; ++i) {
179     		TRACE(ft_t_noise, "eof mark: %5d/%2d",
180     			GET2(&zft_eof_map[i].mark.segment, 0), 
181     			GET2(&zft_eof_map[i].mark.date,0));
182     	}
183     	TRACE_EXIT;
184     }
185     
186     void zft_clear_ftape_file_marks(void)
187     {
188     	TRACE_FUN(ft_t_flow);
189     	/*  Clear failed sector log: remove all tape marks. We
190     	 *  don't use old ftape-style EOF-marks.
191     	 */
192     	TRACE(ft_t_info, "Clearing old ftape's eof map");
193     	memset(zft_eof_map, 0, zft_nr_eof_marks * sizeof(__u32));
194     	zft_nr_eof_marks = 0;
195     	PUT2(zft_hseg_buf, FT_FSL_CNT, 0); /* nr of eof-marks */
196     	zft_header_changed = 1;
197     	zft_update_label(zft_hseg_buf);
198     	TRACE_EXIT;
199     }
200