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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [char/] [ftape/] [lowlevel/] [ftape-bsm.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *      Copyright (C) 1994-1996 Bas Laarhoven,
3
 *                (C) 1996-1997 Claus Heine.
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
 *
20
 * $Source: /home/marcus/revision_ctrl_test/oc_cvs/cvs/or1k/linux/linux-2.4/drivers/char/ftape/lowlevel/ftape-bsm.c,v $
21
 * $Revision: 1.1.1.1 $
22
 * $Date: 2004-04-15 02:02:36 $
23
 *
24
 *      This file contains the bad-sector map handling code for
25
 *      the QIC-117 floppy tape driver for Linux.
26
 *      QIC-40, QIC-80, QIC-3010 and QIC-3020 maps are implemented.
27
 */
28
 
29
#include <linux/string.h>
30
 
31
#include <linux/ftape.h>
32
#include "../lowlevel/ftape-tracing.h"
33
#include "../lowlevel/ftape-bsm.h"
34
#include "../lowlevel/ftape-ctl.h"
35
#include "../lowlevel/ftape-rw.h"
36
 
37
/*      Global vars.
38
 */
39
 
40
/*      Local vars.
41
 */
42
static __u8 *bad_sector_map;
43
static SectorCount *bsm_hash_ptr;
44
 
45
typedef enum {
46
        forward, backward
47
} mode_type;
48
 
49
#if 0
50
/*  fix_tape converts a normal QIC-80 tape into a 'wide' tape.
51
 *  For testing purposes only !
52
 */
53
void fix_tape(__u8 * buffer, ft_format_type new_code)
54
{
55
        static __u8 list[BAD_SECTOR_MAP_SIZE];
56
        SectorMap *src_ptr = (SectorMap *) list;
57
        __u8 *dst_ptr = bad_sector_map;
58
        SectorMap map;
59
        unsigned int sector = 1;
60
        int i;
61
 
62
        if (format_code != fmt_var && format_code != fmt_big) {
63
                memcpy(list, bad_sector_map, sizeof(list));
64
                memset(bad_sector_map, 0, sizeof(bad_sector_map));
65
                while ((__u8 *) src_ptr - list < sizeof(list)) {
66
                        map = *src_ptr++;
67
                        if (map == EMPTY_SEGMENT) {
68
                                *(SectorMap *) dst_ptr = 0x800000 + sector;
69
                                dst_ptr += 3;
70
                                sector += SECTORS_PER_SEGMENT;
71
                        } else {
72
                                for (i = 0; i < SECTORS_PER_SEGMENT; ++i) {
73
                                        if (map & 1) {
74
                                                *(SewctorMap *) dst_ptr = sector;
75
                                                dst_ptr += 3;
76
                                        }
77
                                        map >>= 1;
78
                                        ++sector;
79
                                }
80
                        }
81
                }
82
        }
83
        bad_sector_map_changed = 1;
84
        *(buffer + 4) = new_code;       /* put new format code */
85
        if (format_code != fmt_var && new_code == fmt_big) {
86
                PUT4(buffer, FT_6_HSEG_1,   (__u32)GET2(buffer, 6));
87
                PUT4(buffer, FT_6_HSEG_2,   (__u32)GET2(buffer, 8));
88
                PUT4(buffer, FT_6_FRST_SEG, (__u32)GET2(buffer, 10));
89
                PUT4(buffer, FT_6_LAST_SEG, (__u32)GET2(buffer, 12));
90
                memset(buffer+6, '\0', 8);
91
        }
92
        format_code = new_code;
93
}
94
 
95
#endif
96
 
97
/*   given buffer that contains a header segment, find the end of
98
 *   of the bsm list
99
 */
100
__u8 * ftape_find_end_of_bsm_list(__u8 * address)
101
{
102
        __u8 *ptr   = address + FT_HEADER_END; /* start of bsm list */
103
        __u8 *limit = address + FT_SEGMENT_SIZE;
104
        while (ptr + 2 < limit) {
105
                if (ptr[0] || ptr[1] || ptr[2]) {
106
                        ptr += 3;
107
                } else {
108
                        return ptr;
109
                }
110
        }
111
        return NULL;
112
}
113
 
114
static inline void put_sector(SectorCount *ptr, unsigned int sector)
115
{
116
        ptr->bytes[0] = sector & 0xff;
117
        sector >>= 8;
118
        ptr->bytes[1] = sector & 0xff;
119
        sector >>= 8;
120
        ptr->bytes[2] = sector & 0xff;
121
}
122
 
123
static inline unsigned int get_sector(SectorCount *ptr)
124
{
125
#if 1
126
        unsigned int sector;
127
 
128
        sector  = ptr->bytes[0];
129
        sector += ptr->bytes[1] <<  8;
130
        sector += ptr->bytes[2] << 16;
131
 
132
        return sector;
133
#else
134
        /*  GET4 gets the next four bytes in Intel little endian order
135
         *  and converts them to host byte order and handles unaligned
136
         *  access.
137
         */
138
        return (GET4(ptr, 0) & 0x00ffffff); /* back to host byte order */
139
#endif
140
}
141
 
142
static void bsm_debug_fake(void)
143
{
144
        /* for testing of bad sector handling at end of tape
145
         */
146
#if 0
147
        ftape_put_bad_sector_entry(segments_per_track * tracks_per_tape - 3,
148
                                   0x000003e0;
149
        ftape_put_bad_sector_entry(segments_per_track * tracks_per_tape - 2,
150
                                   0xff3fffff;
151
        ftape_put_bad_sector_entry(segments_per_track * tracks_per_tape - 1,
152
                                   0xffffe000;
153
#endif
154
        /*  Enable to test bad sector handling
155
         */
156
#if 0
157
        ftape_put_bad_sector_entry(30, 0xfffffffe)
158
        ftape_put_bad_sector_entry(32, 0x7fffffff);
159
        ftape_put_bad_sector_entry(34, 0xfffeffff);
160
        ftape_put_bad_sector_entry(36, 0x55555555);
161
        ftape_put_bad_sector_entry(38, 0xffffffff);
162
        ftape_put_bad_sector_entry(50, 0xffff0000);
163
        ftape_put_bad_sector_entry(51, 0xffffffff);
164
        ftape_put_bad_sector_entry(52, 0xffffffff);
165
        ftape_put_bad_sector_entry(53, 0x0000ffff);
166
#endif
167
        /*  Enable when testing multiple volume tar dumps.
168
         */
169
#if 0
170
        {
171
                int i;
172
 
173
                for (i = ft_first_data_segment;
174
                     i <= ft_last_data_segment - 7; ++i) {
175
                        ftape_put_bad_sector_entry(i, EMPTY_SEGMENT);
176
                }
177
        }
178
#endif
179
        /*  Enable when testing bit positions in *_error_map
180
         */
181
#if 0
182
        {
183
                int i;
184
 
185
                for (i = first_data_segment; i <= last_data_segment; ++i) {
186
                        ftape_put_bad_sector_entry(i,
187
                                           ftape_get_bad_sector_entry(i)
188
                                           | 0x00ff00ff);
189
                }
190
        }
191
#endif
192
}
193
 
194
static void print_bad_sector_map(void)
195
{
196
        unsigned int good_sectors;
197
        unsigned int total_bad = 0;
198
        int i;
199
        TRACE_FUN(ft_t_flow);
200
 
201
        if (ft_format_code == fmt_big ||
202
            ft_format_code == fmt_var ||
203
            ft_format_code == fmt_1100ft) {
204
                SectorCount *ptr = (SectorCount *)bad_sector_map;
205
                unsigned int sector;
206
 
207
                while((sector = get_sector(ptr++)) != 0) {
208
                        if ((ft_format_code == fmt_big ||
209
                             ft_format_code == fmt_var) &&
210
                            sector & 0x800000) {
211
                                total_bad += FT_SECTORS_PER_SEGMENT - 3;
212
                                TRACE(ft_t_noise, "bad segment at sector: %6d",
213
                                      sector & 0x7fffff);
214
                        } else {
215
                                ++total_bad;
216
                                TRACE(ft_t_noise, "bad sector: %6d", sector);
217
                        }
218
                }
219
                /*  Display old ftape's end-of-file marks
220
                 */
221
                while ((sector = get_unaligned(((__u16*)ptr)++)) != 0) {
222
                        TRACE(ft_t_noise, "Old ftape eof mark: %4d/%2d",
223
                              sector, get_unaligned(((__u16*)ptr)++));
224
                }
225
        } else { /* fixed size format */
226
                for (i = ft_first_data_segment;
227
                     i < (int)(ft_segments_per_track * ft_tracks_per_tape); ++i) {
228
                        SectorMap map = ((SectorMap *) bad_sector_map)[i];
229
 
230
                        if (map) {
231
                                TRACE(ft_t_noise,
232
                                      "bsm for segment %4d: 0x%08x", i, (unsigned int)map);
233
                                total_bad += ((map == EMPTY_SEGMENT)
234
                                               ? FT_SECTORS_PER_SEGMENT - 3
235
                                               : count_ones(map));
236
                        }
237
                }
238
        }
239
        good_sectors =
240
                ((ft_segments_per_track * ft_tracks_per_tape - ft_first_data_segment)
241
                 * (FT_SECTORS_PER_SEGMENT - 3)) - total_bad;
242
        TRACE(ft_t_info, "%d Kb usable on this tape", good_sectors);
243
        if (total_bad == 0) {
244
                TRACE(ft_t_info,
245
                      "WARNING: this tape has no bad blocks registered !");
246
        } else {
247
                TRACE(ft_t_info, "%d bad sectors", total_bad);
248
        }
249
        TRACE_EXIT;
250
}
251
 
252
 
253
void ftape_extract_bad_sector_map(__u8 * buffer)
254
{
255
        TRACE_FUN(ft_t_any);
256
 
257
        /*  Fill the bad sector map with the contents of buffer.
258
         */
259
        if (ft_format_code == fmt_var || ft_format_code == fmt_big) {
260
                /* QIC-3010/3020 and wide QIC-80 tapes no longer have a failed
261
                 * sector log but use this area to extend the bad sector map.
262
                 */
263
                bad_sector_map = &buffer[FT_HEADER_END];
264
        } else {
265
                /* non-wide QIC-80 tapes have a failed sector log area that
266
                 * mustn't be included in the bad sector map.
267
                 */
268
                bad_sector_map = &buffer[FT_FSL + FT_FSL_SIZE];
269
        }
270
        if (ft_format_code == fmt_1100ft ||
271
            ft_format_code == fmt_var    ||
272
            ft_format_code == fmt_big) {
273
                bsm_hash_ptr = (SectorCount *)bad_sector_map;
274
        } else {
275
                bsm_hash_ptr = NULL;
276
        }
277
        bsm_debug_fake();
278
        if (TRACE_LEVEL >= ft_t_info) {
279
                print_bad_sector_map();
280
        }
281
        TRACE_EXIT;
282
}
283
 
284
static inline SectorMap cvt2map(unsigned int sector)
285
{
286
        return 1 << (((sector & 0x7fffff) - 1) % FT_SECTORS_PER_SEGMENT);
287
}
288
 
289
static inline int cvt2segment(unsigned int sector)
290
{
291
        return ((sector & 0x7fffff) - 1) / FT_SECTORS_PER_SEGMENT;
292
}
293
 
294
static int forward_seek_entry(int segment_id,
295
                              SectorCount **ptr,
296
                              SectorMap *map)
297
{
298
        unsigned int sector;
299
        int segment;
300
 
301
        do {
302
                sector = get_sector((*ptr)++);
303
                segment = cvt2segment(sector);
304
        } while (sector != 0 && segment < segment_id);
305
        (*ptr) --; /* point to first sector >= segment_id */
306
        /*  Get all sectors in segment_id
307
         */
308
        if (sector == 0 || segment != segment_id) {
309
                *map = 0;
310
                return 0;
311
        } else if ((sector & 0x800000) &&
312
                   (ft_format_code == fmt_var || ft_format_code == fmt_big)) {
313
                *map = EMPTY_SEGMENT;
314
                return FT_SECTORS_PER_SEGMENT;
315
        } else {
316
                int count = 1;
317
                SectorCount *tmp_ptr = (*ptr) + 1;
318
 
319
                *map = cvt2map(sector);
320
                while ((sector = get_sector(tmp_ptr++)) != 0 &&
321
                       (segment = cvt2segment(sector)) == segment_id) {
322
                        *map |= cvt2map(sector);
323
                        ++count;
324
                }
325
                return count;
326
        }
327
}
328
 
329
static int backwards_seek_entry(int segment_id,
330
                                SectorCount **ptr,
331
                                SectorMap *map)
332
{
333
        unsigned int sector;
334
        int segment; /* max unsigned int */
335
 
336
        if (*ptr <= (SectorCount *)bad_sector_map) {
337
                *map = 0;
338
                return 0;
339
        }
340
        do {
341
                sector  = get_sector(--(*ptr));
342
                segment = cvt2segment(sector);
343
        } while (*ptr > (SectorCount *)bad_sector_map && segment > segment_id);
344
        if (segment > segment_id) { /*  at start of list, no entry found */
345
                *map = 0;
346
                return 0;
347
        } else if (segment < segment_id) {
348
                /*  before smaller entry, adjust for overshoot */
349
                (*ptr) ++;
350
                *map = 0;
351
                return 0;
352
        } else if ((sector & 0x800000) &&
353
                   (ft_format_code == fmt_big || ft_format_code == fmt_var)) {
354
                *map = EMPTY_SEGMENT;
355
                return FT_SECTORS_PER_SEGMENT;
356
        } else { /*  get all sectors in segment_id */
357
                int count = 1;
358
 
359
                *map = cvt2map(sector);
360
                while(*ptr > (SectorCount *)bad_sector_map) {
361
                        sector = get_sector(--(*ptr));
362
                        segment = cvt2segment(sector);
363
                        if (segment != segment_id) {
364
                                break;
365
                        }
366
                        *map |= cvt2map(sector);
367
                        ++count;
368
                }
369
                if (segment < segment_id) {
370
                        (*ptr) ++;
371
                }
372
                return count;
373
        }
374
}
375
 
376
void ftape_put_bad_sector_entry(int segment_id, SectorMap new_map)
377
{
378
        SectorCount *ptr = (SectorCount *)bad_sector_map;
379
        int count;
380
        int new_count;
381
        SectorMap map;
382
        TRACE_FUN(ft_t_any);
383
 
384
        if (ft_format_code == fmt_1100ft ||
385
            ft_format_code == fmt_var ||
386
            ft_format_code == fmt_big) {
387
                count = forward_seek_entry(segment_id, &ptr, &map);
388
                new_count = count_ones(new_map);
389
                /* If format code == 4 put empty segment instead of 32
390
                 * bad sectors.
391
                 */
392
                if (ft_format_code == fmt_var || ft_format_code == fmt_big) {
393
                        if (new_count == FT_SECTORS_PER_SEGMENT) {
394
                                new_count = 1;
395
                        }
396
                        if (count == FT_SECTORS_PER_SEGMENT) {
397
                                count = 1;
398
                        }
399
                }
400
                if (count != new_count) {
401
                        /* insert (or delete if < 0) new_count - count
402
                         * entries.  Move trailing part of list
403
                         * including terminating 0.
404
                         */
405
                        SectorCount *hi_ptr = ptr;
406
 
407
                        do {
408
                        } while (get_sector(hi_ptr++) != 0);
409
                        /*  Note: ptr is of type byte *, and each bad sector
410
                         *  consumes 3 bytes.
411
                         */
412
                        memmove(ptr + new_count, ptr + count,
413
                                (size_t)(hi_ptr - (ptr + count))*sizeof(SectorCount));
414
                }
415
                TRACE(ft_t_noise, "putting map 0x%08x at %p, segment %d",
416
                      (unsigned int)new_map, ptr, segment_id);
417
                if (new_count == 1 && new_map == EMPTY_SEGMENT) {
418
                        put_sector(ptr++, (0x800001 +
419
                                          segment_id *
420
                                          FT_SECTORS_PER_SEGMENT));
421
                } else {
422
                        int i = 0;
423
 
424
                        while (new_map) {
425
                                if (new_map & 1) {
426
                                        put_sector(ptr++,
427
                                                   1 + segment_id *
428
                                                   FT_SECTORS_PER_SEGMENT + i);
429
                                }
430
                                ++i;
431
                                new_map >>= 1;
432
                        }
433
                }
434
        } else {
435
                ((SectorMap *) bad_sector_map)[segment_id] = new_map;
436
        }
437
        TRACE_EXIT;
438
}
439
 
440
SectorMap ftape_get_bad_sector_entry(int segment_id)
441
{
442
        if (ft_used_header_segment == -1) {
443
                /*  When reading header segment we'll need a blank map.
444
                 */
445
                return 0;
446
        } else if (bsm_hash_ptr != NULL) {
447
                /*  Invariants:
448
                 *    map - mask value returned on last call.
449
                 *    bsm_hash_ptr - points to first sector greater or equal to
450
                 *          first sector in last_referenced segment.
451
                 *    last_referenced - segment id used in the last call,
452
                 *                      sector and map belong to this id.
453
                 *  This code is designed for sequential access and retries.
454
                 *  For true random access it may have to be redesigned.
455
                 */
456
                static int last_reference = -1;
457
                static SectorMap map;
458
 
459
                if (segment_id > last_reference) {
460
                        /*  Skip all sectors before segment_id
461
                         */
462
                        forward_seek_entry(segment_id, &bsm_hash_ptr, &map);
463
                } else if (segment_id < last_reference) {
464
                        /* Skip backwards until begin of buffer or
465
                         * first sector in segment_id
466
                         */
467
                        backwards_seek_entry(segment_id, &bsm_hash_ptr, &map);
468
                }               /* segment_id == last_reference : keep map */
469
                last_reference = segment_id;
470
                return map;
471
        } else {
472
                return ((SectorMap *) bad_sector_map)[segment_id];
473
        }
474
}
475
 
476
/*  This is simply here to prevent us from overwriting other kernel
477
 *  data. Writes will result in NULL Pointer dereference.
478
 */
479
void ftape_init_bsm(void)
480
{
481
        bad_sector_map = NULL;
482
        bsm_hash_ptr   = NULL;
483
}

powered by: WebSVN 2.1.0

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