1 |
1626 |
jcastillo |
|
2 |
|
|
/*
|
3 |
|
|
* Copyright (C) 1994-1995 Bas Laarhoven.
|
4 |
|
|
|
5 |
|
|
This program is free software; you can redistribute it and/or modify
|
6 |
|
|
it under the terms of the GNU General Public License as published by
|
7 |
|
|
the Free Software Foundation; either version 2, or (at your option)
|
8 |
|
|
any later version.
|
9 |
|
|
|
10 |
|
|
This program is distributed in the hope that it will be useful,
|
11 |
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12 |
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13 |
|
|
GNU General Public License for more details.
|
14 |
|
|
|
15 |
|
|
You should have received a copy of the GNU General Public License
|
16 |
|
|
along with this program; see the file COPYING. If not, write to
|
17 |
|
|
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
18 |
|
|
|
19 |
|
|
$Source: /home/marcus/revision_ctrl_test/oc_cvs/cvs/or1k/rc203soc/sw/uClinux/drivers/char/ftape/ftape-eof.c,v $
|
20 |
|
|
$Author: jcastillo $
|
21 |
|
|
*
|
22 |
|
|
$Revision: 1.1 $
|
23 |
|
|
$Date: 2005-12-20 10:16:52 $
|
24 |
|
|
$State: Exp $
|
25 |
|
|
*
|
26 |
|
|
* This file contains the eof mark handling code
|
27 |
|
|
* for the QIC-40/80 floppy-tape driver for Linux.
|
28 |
|
|
*/
|
29 |
|
|
|
30 |
|
|
#include <linux/ftape.h>
|
31 |
|
|
#include <linux/string.h>
|
32 |
|
|
#include <linux/errno.h>
|
33 |
|
|
|
34 |
|
|
#include "tracing.h"
|
35 |
|
|
#include "ftape-eof.h"
|
36 |
|
|
#include "ftape-write.h"
|
37 |
|
|
#include "ftape-read.h"
|
38 |
|
|
#include "ftape-rw.h"
|
39 |
|
|
#include "ftape-ctl.h"
|
40 |
|
|
#include "ftape-bsm.h"
|
41 |
|
|
|
42 |
|
|
/* Global vars.
|
43 |
|
|
*/
|
44 |
|
|
int failed_sector_log_changed = 0;
|
45 |
|
|
int eof_mark = 0;
|
46 |
|
|
|
47 |
|
|
/* Local vars.
|
48 |
|
|
*/
|
49 |
|
|
static struct failed_sector_entry {
|
50 |
|
|
unsigned short segment;
|
51 |
|
|
unsigned short sector;
|
52 |
|
|
} *eof_mark_ptr;
|
53 |
|
|
|
54 |
|
|
typedef union {
|
55 |
|
|
struct failed_sector_entry mark;
|
56 |
|
|
unsigned long entry;
|
57 |
|
|
} eof_mark_union;
|
58 |
|
|
|
59 |
|
|
/* a copy of the failed sector log from the header segment.
|
60 |
|
|
*/
|
61 |
|
|
static eof_mark_union eof_map[(2048 - 256) / 4];
|
62 |
|
|
|
63 |
|
|
/* index into eof_map table pointing to last found eof mark.
|
64 |
|
|
*/
|
65 |
|
|
static int eof_index;
|
66 |
|
|
|
67 |
|
|
/* number of eof marks (entries in bad sector log) on tape.
|
68 |
|
|
*/
|
69 |
|
|
static int nr_of_eof_marks = -1;
|
70 |
|
|
|
71 |
|
|
static char linux_tape_label[] = "Linux raw format V";
|
72 |
|
|
enum {
|
73 |
|
|
min_fmt_version = 1, max_fmt_version = 2
|
74 |
|
|
};
|
75 |
|
|
static unsigned ftape_fmt_version = 0;
|
76 |
|
|
|
77 |
|
|
|
78 |
|
|
/* Ftape (mis)uses the bad sector log to record end-of-file marks.
|
79 |
|
|
* Initially (when the tape is erased) all entries in the bad sector
|
80 |
|
|
* log are added to the tape's bad sector map. The bad sector log
|
81 |
|
|
* then is cleared.
|
82 |
|
|
*
|
83 |
|
|
* The bad sector log normally contains entries of the form:
|
84 |
|
|
* even 16-bit word: segment number of bad sector
|
85 |
|
|
* odd 16-bit word: encoded date
|
86 |
|
|
* There can be a total of 448 entries (1792 bytes).
|
87 |
|
|
*
|
88 |
|
|
* My guess is that no program is using this bad sector log (the
|
89 |
|
|
* format seems useless as there is no indication of the bad sector
|
90 |
|
|
* itself, only the segment)
|
91 |
|
|
* However, if any program does use the bad sector log, the format
|
92 |
|
|
* used by ftape will let the program think there are some bad sectors
|
93 |
|
|
* and no harm is done.
|
94 |
|
|
*
|
95 |
|
|
* The eof mark entries that ftape stores in the bad sector log:
|
96 |
|
|
* even 16-bit word: segment number of eof mark
|
97 |
|
|
* odd 16-bit word: sector number of eof mark [1..32]
|
98 |
|
|
*
|
99 |
|
|
* The eof_map as maintained is a sorted list of eof mark entries.
|
100 |
|
|
*
|
101 |
|
|
*
|
102 |
|
|
* The tape name field in the header segments is used to store a
|
103 |
|
|
* linux tape identification string and a version number.
|
104 |
|
|
* This way the tape can be recognized as a Linux raw format
|
105 |
|
|
* tape when using tools under other OS's.
|
106 |
|
|
*
|
107 |
|
|
* 'Wide' QIC tapes (format code 4) don't have a failed sector list
|
108 |
|
|
* anymore. That space is used for the (longer) bad sector map that
|
109 |
|
|
* now is a variable length list too.
|
110 |
|
|
* We now store our end-of-file marker list after the bad-sector-map
|
111 |
|
|
* on tape. The list is delimited by a (long) 0 entry.
|
112 |
|
|
*/
|
113 |
|
|
|
114 |
|
|
int ftape_validate_label(char *label)
|
115 |
|
|
{
|
116 |
|
|
TRACE_FUN(8, "ftape_validate_label");
|
117 |
|
|
int result = 0;
|
118 |
|
|
|
119 |
|
|
TRACEx1(4, "tape label = `%s'", label);
|
120 |
|
|
ftape_fmt_version = 0;
|
121 |
|
|
if (memcmp(label, linux_tape_label, strlen(linux_tape_label)) == 0) {
|
122 |
|
|
int pos = strlen(linux_tape_label);
|
123 |
|
|
while (label[pos] >= '0' && label[pos] <= '9') {
|
124 |
|
|
ftape_fmt_version *= 10;
|
125 |
|
|
ftape_fmt_version = label[pos++] - '0';
|
126 |
|
|
}
|
127 |
|
|
result = (ftape_fmt_version >= min_fmt_version &&
|
128 |
|
|
ftape_fmt_version <= max_fmt_version);
|
129 |
|
|
}
|
130 |
|
|
TRACEx1(4, "format version = %d", ftape_fmt_version);
|
131 |
|
|
TRACE_EXIT;
|
132 |
|
|
return result;
|
133 |
|
|
}
|
134 |
|
|
|
135 |
|
|
static byte *
|
136 |
|
|
find_end_of_eof_list(byte * ptr, byte * limit)
|
137 |
|
|
{
|
138 |
|
|
while (ptr + 3 < limit) {
|
139 |
|
|
if (*(unsigned long *) ptr) {
|
140 |
|
|
++(unsigned long *) ptr;
|
141 |
|
|
} else {
|
142 |
|
|
return ptr;
|
143 |
|
|
}
|
144 |
|
|
}
|
145 |
|
|
return NULL;
|
146 |
|
|
}
|
147 |
|
|
|
148 |
|
|
void reset_eof_list(void)
|
149 |
|
|
{
|
150 |
|
|
TRACE_FUN(8, "reset_eof_list");
|
151 |
|
|
|
152 |
|
|
eof_mark_ptr = &eof_map[0].mark;
|
153 |
|
|
eof_index = 0;
|
154 |
|
|
eof_mark = 0;
|
155 |
|
|
TRACE_EXIT;
|
156 |
|
|
}
|
157 |
|
|
|
158 |
|
|
/* Test if `segment' has an eof mark set (optimized for sequential access).
|
159 |
|
|
* return 0 if not eof mark or sector number (> 0) if eof mark set.
|
160 |
|
|
*/
|
161 |
|
|
int check_for_eof(unsigned segment)
|
162 |
|
|
{
|
163 |
|
|
TRACE_FUN(8, "check_for_eof");
|
164 |
|
|
static unsigned last_reference = INT_MAX;
|
165 |
|
|
int result;
|
166 |
|
|
|
167 |
|
|
if (segment < last_reference) {
|
168 |
|
|
reset_eof_list();
|
169 |
|
|
}
|
170 |
|
|
last_reference = segment;
|
171 |
|
|
while (eof_index < nr_of_eof_marks && segment > eof_mark_ptr->segment) {
|
172 |
|
|
++eof_mark_ptr;
|
173 |
|
|
++eof_index;
|
174 |
|
|
}
|
175 |
|
|
if (eof_index < nr_of_eof_marks && segment == eof_mark_ptr->segment) {
|
176 |
|
|
TRACEx3(5, "hit mark %d/%d at index %d",
|
177 |
|
|
eof_map[eof_index].mark.segment, eof_map[eof_index].mark.sector,
|
178 |
|
|
eof_index);
|
179 |
|
|
if (eof_mark_ptr->sector >= SECTORS_PER_SEGMENT) {
|
180 |
|
|
TRACEx2(-1, "Bad file mark detected: %d/%d",
|
181 |
|
|
eof_mark_ptr->segment, eof_mark_ptr->sector);
|
182 |
|
|
result = 0; /* return bogus (but valid) value */
|
183 |
|
|
} else {
|
184 |
|
|
result = eof_mark_ptr->sector;
|
185 |
|
|
}
|
186 |
|
|
} else {
|
187 |
|
|
result = 0;
|
188 |
|
|
}
|
189 |
|
|
TRACE_EXIT;
|
190 |
|
|
return result;
|
191 |
|
|
}
|
192 |
|
|
|
193 |
|
|
void clear_eof_mark_if_set(unsigned segment, unsigned byte_count)
|
194 |
|
|
{
|
195 |
|
|
TRACE_FUN(5, "clear_eof_mark_if_set");
|
196 |
|
|
if (ftape_fmt_version != 0 &&
|
197 |
|
|
check_for_eof(segment) > 0 &&
|
198 |
|
|
byte_count >= eof_mark_ptr->sector * SECTOR_SIZE) {
|
199 |
|
|
TRACEx3(5, "clearing mark %d/%d at index %d",
|
200 |
|
|
eof_mark_ptr->segment, eof_mark_ptr->sector, eof_index);
|
201 |
|
|
memmove(&eof_map[eof_index], &eof_map[eof_index + 1],
|
202 |
|
|
(nr_of_eof_marks - eof_index) * sizeof(*eof_map));
|
203 |
|
|
--nr_of_eof_marks;
|
204 |
|
|
failed_sector_log_changed = 1;
|
205 |
|
|
}
|
206 |
|
|
TRACE_EXIT;
|
207 |
|
|
}
|
208 |
|
|
|
209 |
|
|
void put_file_mark_in_map(unsigned segment, unsigned sector)
|
210 |
|
|
{
|
211 |
|
|
TRACE_FUN(8, "put_file_mark_in_map");
|
212 |
|
|
eof_mark_union new;
|
213 |
|
|
int index;
|
214 |
|
|
eof_mark_union *ptr;
|
215 |
|
|
|
216 |
|
|
if (ftape_fmt_version != 0) {
|
217 |
|
|
new.mark.segment = segment;
|
218 |
|
|
new.mark.sector = sector;
|
219 |
|
|
for (index = 0, ptr = &eof_map[0];
|
220 |
|
|
index < nr_of_eof_marks && ptr->mark.segment < segment;
|
221 |
|
|
++index, ++ptr) {
|
222 |
|
|
}
|
223 |
|
|
if (index < nr_of_eof_marks) {
|
224 |
|
|
if (ptr->mark.segment == segment) {
|
225 |
|
|
/* overwrite */
|
226 |
|
|
if (ptr->mark.sector == sector) {
|
227 |
|
|
TRACEx2(5, "mark %d/%d already exists",
|
228 |
|
|
new.mark.segment, new.mark.sector);
|
229 |
|
|
} else {
|
230 |
|
|
TRACEx5(5, "overwriting %d/%d at index %d with %d/%d",
|
231 |
|
|
ptr->mark.segment, ptr->mark.sector, index,
|
232 |
|
|
new.mark.segment, new.mark.sector);
|
233 |
|
|
ptr->entry = new.entry;
|
234 |
|
|
failed_sector_log_changed = 1;
|
235 |
|
|
}
|
236 |
|
|
} else {
|
237 |
|
|
/* insert */
|
238 |
|
|
TRACEx5(5, "inserting %d/%d at index %d before %d/%d",
|
239 |
|
|
new.mark.segment, new.mark.sector, index,
|
240 |
|
|
ptr->mark.segment, ptr->mark.sector);
|
241 |
|
|
memmove(ptr + 1, ptr, (nr_of_eof_marks - index) * sizeof(*eof_map));
|
242 |
|
|
ptr->entry = new.entry;
|
243 |
|
|
++nr_of_eof_marks;
|
244 |
|
|
failed_sector_log_changed = 1;
|
245 |
|
|
}
|
246 |
|
|
} else {
|
247 |
|
|
/* append */
|
248 |
|
|
TRACEx3(5, "appending %d/%d at index %d",
|
249 |
|
|
new.mark.segment, new.mark.sector, index);
|
250 |
|
|
ptr->entry = new.entry;
|
251 |
|
|
++nr_of_eof_marks;
|
252 |
|
|
failed_sector_log_changed = 1;
|
253 |
|
|
}
|
254 |
|
|
}
|
255 |
|
|
TRACE_EXIT;
|
256 |
|
|
}
|
257 |
|
|
|
258 |
|
|
/* Write count file marks to tape starting at first non-bad
|
259 |
|
|
* sector following the given segment and sector.
|
260 |
|
|
* sector = base 1 !
|
261 |
|
|
*/
|
262 |
|
|
int ftape_weof(unsigned count, unsigned segment, unsigned sector)
|
263 |
|
|
{
|
264 |
|
|
TRACE_FUN(5, "ftape_weof");
|
265 |
|
|
int result = 0;
|
266 |
|
|
unsigned long mask = get_bad_sector_entry(segment);
|
267 |
|
|
unsigned sector_nr = 0;
|
268 |
|
|
|
269 |
|
|
if (ftape_fmt_version != 0) {
|
270 |
|
|
if (sector < 1 || sector > 29 ||
|
271 |
|
|
segment + count >= ftape_last_segment.id) {
|
272 |
|
|
TRACEx3(5, "parameter out of range: %d, %d, %d", count, segment, sector);
|
273 |
|
|
result = -EIO;
|
274 |
|
|
} else {
|
275 |
|
|
while (count-- > 0) {
|
276 |
|
|
do { /* count logical sectors */
|
277 |
|
|
do { /* skip until good sector */
|
278 |
|
|
while (mask & 1) { /* skip bad sectors */
|
279 |
|
|
++sector_nr;
|
280 |
|
|
mask >>= 1;
|
281 |
|
|
}
|
282 |
|
|
if (sector_nr >= 29) {
|
283 |
|
|
if (++segment >= ftape_last_segment.id) {
|
284 |
|
|
TRACEx1(5, "segment out of range: %d", segment);
|
285 |
|
|
result = -EIO;
|
286 |
|
|
break;
|
287 |
|
|
}
|
288 |
|
|
mask = get_bad_sector_entry(segment);
|
289 |
|
|
sector_nr = 0;
|
290 |
|
|
}
|
291 |
|
|
} while (mask & 1);
|
292 |
|
|
++sector_nr; /* point to good sector */
|
293 |
|
|
mask >>= 1;
|
294 |
|
|
} while (--sector);
|
295 |
|
|
if (result >= 0) {
|
296 |
|
|
TRACEx2(5, "writing filemark %d/%d", segment, sector_nr);
|
297 |
|
|
put_file_mark_in_map(segment, sector_nr);
|
298 |
|
|
++segment; /* next segment */
|
299 |
|
|
sector_nr = 0;
|
300 |
|
|
sector = 1; /* first sector */
|
301 |
|
|
}
|
302 |
|
|
}
|
303 |
|
|
}
|
304 |
|
|
} else {
|
305 |
|
|
result = -EPERM;
|
306 |
|
|
}
|
307 |
|
|
TRACE_EXIT;
|
308 |
|
|
return result;
|
309 |
|
|
}
|
310 |
|
|
|
311 |
|
|
int ftape_erase(void)
|
312 |
|
|
{
|
313 |
|
|
TRACE_FUN(5, "ftape_erase");
|
314 |
|
|
int result = 0;
|
315 |
|
|
int i;
|
316 |
|
|
unsigned long now = 0;
|
317 |
|
|
byte *buffer = deblock_buffer;
|
318 |
|
|
|
319 |
|
|
if (write_protected) {
|
320 |
|
|
result = -EROFS;
|
321 |
|
|
} else {
|
322 |
|
|
result = read_header_segment(buffer);
|
323 |
|
|
if (result >= 0) {
|
324 |
|
|
/* Copy entries from bad-sector-log into bad-sector-map
|
325 |
|
|
*/
|
326 |
|
|
TRACEx1(5, "old label: `%s'", (char *) (buffer + 30));
|
327 |
|
|
if (!ftape_validate_label((char *) &buffer[30])) {
|
328 |
|
|
TRACE(5, "invalid label, overwriting with new");
|
329 |
|
|
memset(buffer + 30, 0, 44);
|
330 |
|
|
memcpy(buffer + 30, linux_tape_label, strlen(linux_tape_label));
|
331 |
|
|
buffer[30 + strlen(linux_tape_label)] = '2';
|
332 |
|
|
TRACEx1(5, "new label: `%s'", (char *) (buffer + 30));
|
333 |
|
|
PUT4(buffer, 74, now);
|
334 |
|
|
if (format_code != 4) {
|
335 |
|
|
for (i = 0; i < nr_of_eof_marks; ++i) {
|
336 |
|
|
unsigned failing_segment = eof_map[i].mark.segment;
|
337 |
|
|
|
338 |
|
|
if (!valid_segment_no(failing_segment)) {
|
339 |
|
|
TRACEi(4, "bad entry in failed sector log:", failing_segment);
|
340 |
|
|
} else {
|
341 |
|
|
put_bad_sector_entry(failing_segment, EMPTY_SEGMENT);
|
342 |
|
|
TRACEx2(4, "moved entry %d from failed sector log (%d)",
|
343 |
|
|
i, failing_segment);
|
344 |
|
|
}
|
345 |
|
|
}
|
346 |
|
|
}
|
347 |
|
|
}
|
348 |
|
|
/* Clear failed sector log: remove all tape marks
|
349 |
|
|
*/
|
350 |
|
|
failed_sector_log_changed = 1;
|
351 |
|
|
memset(eof_map, 0, sizeof(eof_map));
|
352 |
|
|
nr_of_eof_marks = 0;
|
353 |
|
|
ftape_fmt_version = max_fmt_version;
|
354 |
|
|
#if 0
|
355 |
|
|
fix_tape(buffer); /* see ftape-bsm.c ! */
|
356 |
|
|
#endif
|
357 |
|
|
result = ftape_update_header_segments(buffer, 1);
|
358 |
|
|
prevent_flush(); /* prevent flush_buffers writing file marks */
|
359 |
|
|
reset_eof_list();
|
360 |
|
|
}
|
361 |
|
|
}
|
362 |
|
|
TRACE_EXIT;
|
363 |
|
|
return result;
|
364 |
|
|
}
|
365 |
|
|
|
366 |
|
|
void extract_file_marks(byte * address)
|
367 |
|
|
{
|
368 |
|
|
TRACE_FUN(8, "extract_file_marks");
|
369 |
|
|
int i;
|
370 |
|
|
|
371 |
|
|
if (format_code == 4) {
|
372 |
|
|
byte *end;
|
373 |
|
|
byte *start = find_end_of_bsm_list(address + 256,
|
374 |
|
|
address + 29 * SECTOR_SIZE);
|
375 |
|
|
|
376 |
|
|
memset(eof_map, 0, sizeof(eof_map));
|
377 |
|
|
nr_of_eof_marks = 0;
|
378 |
|
|
if (start) {
|
379 |
|
|
start += 3; /* skip end of list mark */
|
380 |
|
|
end = find_end_of_eof_list(start, address + 29 * SECTOR_SIZE);
|
381 |
|
|
if (end && end - start <= sizeof(eof_map)) {
|
382 |
|
|
nr_of_eof_marks = (end - start) / sizeof(unsigned long);
|
383 |
|
|
memcpy(eof_map, start, end - start);
|
384 |
|
|
} else {
|
385 |
|
|
TRACE(1, "File Mark List is too long or damaged !");
|
386 |
|
|
}
|
387 |
|
|
} else {
|
388 |
|
|
TRACE(1, "Bad Sector List is too long or damaged !");
|
389 |
|
|
}
|
390 |
|
|
} else {
|
391 |
|
|
memcpy(eof_map, address + 256, sizeof(eof_map));
|
392 |
|
|
nr_of_eof_marks = GET2(address, 144);
|
393 |
|
|
}
|
394 |
|
|
TRACEi(4, "number of file marks:", nr_of_eof_marks);
|
395 |
|
|
if (ftape_fmt_version == 1) {
|
396 |
|
|
TRACE(-1, "swapping version 1 fields");
|
397 |
|
|
/* version 1 format uses swapped sector and segment fields, correct that !
|
398 |
|
|
*/
|
399 |
|
|
for (i = 0; i < nr_of_eof_marks; ++i) {
|
400 |
|
|
unsigned short tmp = eof_map[i].mark.segment;
|
401 |
|
|
eof_map[i].mark.segment = eof_map[i].mark.sector;
|
402 |
|
|
eof_map[i].mark.sector = tmp;
|
403 |
|
|
}
|
404 |
|
|
}
|
405 |
|
|
for (i = 0; i < nr_of_eof_marks; ++i) {
|
406 |
|
|
TRACEx2(4, "eof mark: %5d/%2d",
|
407 |
|
|
eof_map[i].mark.segment, eof_map[i].mark.sector);
|
408 |
|
|
}
|
409 |
|
|
reset_eof_list();
|
410 |
|
|
TRACE_EXIT;
|
411 |
|
|
}
|
412 |
|
|
|
413 |
|
|
int update_failed_sector_log(byte * buffer)
|
414 |
|
|
{
|
415 |
|
|
TRACE_FUN(8, "update_failed_sector_log");
|
416 |
|
|
|
417 |
|
|
if (ftape_fmt_version != 0 && failed_sector_log_changed) {
|
418 |
|
|
if (ftape_fmt_version == 1) {
|
419 |
|
|
TRACE(-1, "upgrading version 1 format to version 2");
|
420 |
|
|
/* version 1 will be upgraded to version 2 when written.
|
421 |
|
|
*/
|
422 |
|
|
buffer[30 + strlen(linux_tape_label)] = '2';
|
423 |
|
|
ftape_fmt_version = 2;
|
424 |
|
|
TRACEx1(-1, "new tape label = \"%s\"", &buffer[30]);
|
425 |
|
|
}
|
426 |
|
|
if (format_code == 4) {
|
427 |
|
|
byte *dest = find_end_of_bsm_list(buffer + 256,
|
428 |
|
|
buffer + 29 * SECTOR_SIZE) + 3;
|
429 |
|
|
|
430 |
|
|
if (dest) {
|
431 |
|
|
TRACEx2(4, "eof_map at byte offset %6d, size %d",
|
432 |
|
|
dest - buffer - 256, nr_of_eof_marks * sizeof(unsigned long));
|
433 |
|
|
memcpy(dest, eof_map, nr_of_eof_marks * sizeof(unsigned long));
|
434 |
|
|
PUT4(dest, nr_of_eof_marks * sizeof(unsigned long), 0);
|
435 |
|
|
}
|
436 |
|
|
} else {
|
437 |
|
|
memcpy(buffer + 256, eof_map, sizeof(eof_map));
|
438 |
|
|
PUT2(buffer, 144, nr_of_eof_marks);
|
439 |
|
|
}
|
440 |
|
|
failed_sector_log_changed = 0;
|
441 |
|
|
return 1;
|
442 |
|
|
}
|
443 |
|
|
TRACE_EXIT;
|
444 |
|
|
return 0;
|
445 |
|
|
}
|
446 |
|
|
|
447 |
|
|
int ftape_seek_eom(void)
|
448 |
|
|
{
|
449 |
|
|
TRACE_FUN(5, "ftape_seek_eom");
|
450 |
|
|
int result = 0;
|
451 |
|
|
unsigned eom;
|
452 |
|
|
|
453 |
|
|
if (first_data_segment == -1) {
|
454 |
|
|
result = read_header_segment(deblock_buffer);
|
455 |
|
|
}
|
456 |
|
|
if (result >= 0 && ftape_fmt_version != 0) {
|
457 |
|
|
eom = first_data_segment;
|
458 |
|
|
eof_index = 0;
|
459 |
|
|
eof_mark_ptr = &eof_map[0].mark;
|
460 |
|
|
/* If fresh tape, count should be zero but we don't
|
461 |
|
|
* want to worry about the case it's one.
|
462 |
|
|
*/
|
463 |
|
|
for (eof_index = 1, eof_mark_ptr = &eof_map[1].mark;
|
464 |
|
|
eof_index < nr_of_eof_marks; ++eof_index, ++eof_mark_ptr) {
|
465 |
|
|
/* The eom is recorded as two eof marks in succeeding segments
|
466 |
|
|
* where the second one is always at segment number 1.
|
467 |
|
|
*/
|
468 |
|
|
if (eof_mark_ptr->sector == 1) {
|
469 |
|
|
if (eof_mark_ptr->segment == (eof_mark_ptr - 1)->segment + 1) {
|
470 |
|
|
eom = eof_mark_ptr->segment;
|
471 |
|
|
break;
|
472 |
|
|
}
|
473 |
|
|
}
|
474 |
|
|
}
|
475 |
|
|
ftape_seg_pos = eom;
|
476 |
|
|
TRACEx1(5, "eom found at segment %d", eom);
|
477 |
|
|
} else {
|
478 |
|
|
TRACE(5, "Couldn't get eof mark table");
|
479 |
|
|
result = -EIO;
|
480 |
|
|
}
|
481 |
|
|
TRACE_EXIT;
|
482 |
|
|
return result;
|
483 |
|
|
}
|
484 |
|
|
|
485 |
|
|
int ftape_seek_eof(unsigned count)
|
486 |
|
|
{
|
487 |
|
|
TRACE_FUN(5, "ftape_seek_eof");
|
488 |
|
|
int result = 0;
|
489 |
|
|
enum {
|
490 |
|
|
not = 0, begin, end
|
491 |
|
|
} bad_seek = not;
|
492 |
|
|
|
493 |
|
|
if (first_data_segment == -1) {
|
494 |
|
|
result = read_header_segment(deblock_buffer);
|
495 |
|
|
}
|
496 |
|
|
TRACEx1(5, "tape positioned at segment %d", ftape_seg_pos);
|
497 |
|
|
if (ftape_fmt_version == 0) {
|
498 |
|
|
result = -1;
|
499 |
|
|
}
|
500 |
|
|
if (result >= 0 && count != 0) {
|
501 |
|
|
for (eof_index = 0; eof_index <= nr_of_eof_marks; ++eof_index) {
|
502 |
|
|
if (eof_index == nr_of_eof_marks || /* start seeking after last mark */
|
503 |
|
|
ftape_seg_pos <= eof_map[eof_index].mark.segment) {
|
504 |
|
|
eof_index += count;
|
505 |
|
|
if (eof_index < 1) { /* begin of tape */
|
506 |
|
|
ftape_seg_pos = first_data_segment;
|
507 |
|
|
if (eof_index < 0) { /* `before' begin of tape */
|
508 |
|
|
eof_index = 0;
|
509 |
|
|
bad_seek = begin;
|
510 |
|
|
}
|
511 |
|
|
} else if (eof_index >= nr_of_eof_marks) { /* `after' end of tape */
|
512 |
|
|
ftape_seg_pos = segments_per_track * tracks_per_tape;
|
513 |
|
|
if (eof_index > nr_of_eof_marks) {
|
514 |
|
|
eof_index = nr_of_eof_marks;
|
515 |
|
|
bad_seek = end;
|
516 |
|
|
}
|
517 |
|
|
} else { /* after requested file mark */
|
518 |
|
|
ftape_seg_pos = eof_map[eof_index - 1].mark.segment + 1;
|
519 |
|
|
}
|
520 |
|
|
eof_mark_ptr = &eof_map[eof_index].mark;
|
521 |
|
|
break;
|
522 |
|
|
}
|
523 |
|
|
}
|
524 |
|
|
}
|
525 |
|
|
if (result < 0) {
|
526 |
|
|
TRACE(5, "Couldn't get eof mark table");
|
527 |
|
|
result = -EIO;
|
528 |
|
|
} else if (bad_seek != not) {
|
529 |
|
|
TRACEx1(1, "seek reached %s of tape",
|
530 |
|
|
(bad_seek == begin) ? "begin" : "end");
|
531 |
|
|
result = -EIO;
|
532 |
|
|
} else {
|
533 |
|
|
TRACEx1(5, "tape repositioned to segment %d", ftape_seg_pos);
|
534 |
|
|
}
|
535 |
|
|
TRACE_EXIT;
|
536 |
|
|
return result;
|
537 |
|
|
}
|
538 |
|
|
|
539 |
|
|
int ftape_file_no(daddr_t * f_no, daddr_t * b_no)
|
540 |
|
|
{
|
541 |
|
|
TRACE_FUN(5, "ftape_file_no");
|
542 |
|
|
int result = 0;
|
543 |
|
|
int i;
|
544 |
|
|
|
545 |
|
|
*f_no = eof_index;
|
546 |
|
|
*b_no = ftape_seg_pos;
|
547 |
|
|
TRACEi(4, "number of file marks:", nr_of_eof_marks);
|
548 |
|
|
for (i = 0; i < nr_of_eof_marks; ++i) {
|
549 |
|
|
TRACEx2(4, "eof mark: %5d/%2d",
|
550 |
|
|
eof_map[i].mark.segment, eof_map[i].mark.sector);
|
551 |
|
|
}
|
552 |
|
|
TRACE_EXIT;
|
553 |
|
|
return result;
|
554 |
|
|
}
|