OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [drivers/] [char/] [ftape/] [ftape-eof.c] - Blame information for rev 1626

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
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
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.