ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / 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 compatibility 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                         ptr += sizeof(__u32);
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 }