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

Subversion Repositories or1k

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

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

Line No. Rev Author Line
1 1626 jcastillo
/*
2
 *      Copyright (C) 1994-1995 Bas Laarhoven.
3
 
4
 This program is free software; you can redistribute it and/or modify
5
 it under the terms of the GNU General Public License as published by
6
 the Free Software Foundation; either version 2, or (at your option)
7
 any later version.
8
 
9
 This program is distributed in the hope that it will be useful,
10
 but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 GNU General Public License for more details.
13
 
14
 You should have received a copy of the GNU General Public License
15
 along with this program; see the file COPYING.  If not, write to
16
 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
17
 
18
 $Source: /home/marcus/revision_ctrl_test/oc_cvs/cvs/or1k/rc203soc/sw/uClinux/drivers/char/ftape/ftape-bsm.c,v $
19
 $Author: jcastillo $
20
 *
21
 $Revision: 1.1 $
22
 $Date: 2005-12-20 10:16:52 $
23
 $State: Exp $
24
 *
25
 *      This file contains the bad-sector map handling code for
26
 *      the QIC-117 floppy tape driver for Linux.
27
 *      QIC-40, QIC-80, QIC-3010 and QIC-3020 maps are implemented.
28
 */
29
 
30
#include <linux/ftape.h>
31
#include <linux/string.h>
32
 
33
#include "tracing.h"
34
#include "ftape-bsm.h"
35
#include "ftape-ctl.h"
36
#include "ftape-rw.h"
37
 
38
 
39
/*      Global vars.
40
 */
41
int bad_sector_map_changed = 0;
42
 
43
/*      Local vars.
44
 */
45
static byte bad_sector_map[BAD_SECTOR_MAP_SIZE];
46
typedef enum {
47
        forward, backward
48
} mode_type;
49
 
50
#if 0
51
/*  fix_tape converts a normal QIC-80 tape into a 'wide' tape.
52
 *  For testing purposes only !
53
 */
54
void fix_tape(byte * buffer)
55
{
56
        static byte list[BAD_SECTOR_MAP_SIZE];
57
        unsigned long *src_ptr = (unsigned long *) list;
58
        byte *dst_ptr = bad_sector_map;
59
        unsigned long map;
60
        unsigned sector = 1;
61
        int i;
62
 
63
        memcpy(list, bad_sector_map, sizeof(list));
64
        memset(bad_sector_map, 0, sizeof(bad_sector_map));
65
        while ((byte *) src_ptr - list < sizeof(list)) {
66
                map = *src_ptr++;
67
                if (map == EMPTY_SEGMENT) {
68
                        *(unsigned long *) 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
                                        *(unsigned long *) dst_ptr = sector;
75
                                        dst_ptr += 3;
76
                                }
77
                                map >>= 1;
78
                                ++sector;
79
                        }
80
                }
81
        }
82
        bad_sector_map_changed = 1;
83
        *(buffer + 4) = 4;      /* put new format code */
84
        format_code = 4;
85
}
86
 
87
#endif
88
 
89
byte *
90
 find_end_of_bsm_list(byte * ptr, byte * limit)
91
{
92
        while (ptr + 2 < limit) {
93
                if (ptr[0] || ptr[1] || ptr[2]) {
94
                        ptr += 3;
95
                } else {
96
                        return ptr;
97
                }
98
        }
99
        return NULL;
100
}
101
 
102
void store_bad_sector_map(byte * buffer)
103
{
104
        TRACE_FUN(8, "store_bad_sector_map");
105
        size_t count;
106
        size_t offset;
107
 
108
        /*  Store the bad sector map in buffer.
109
         */
110
        if (format_code == 4) {
111
                offset = 256;
112
                count = sizeof(bad_sector_map);
113
        } else {
114
                offset = 2 * SECTOR_SIZE;       /* skip failed sector log */
115
                count = sizeof(bad_sector_map) - (offset - 256);
116
        }
117
        memcpy(buffer + offset, bad_sector_map, count);
118
        TRACE_EXIT;
119
}
120
 
121
void put_sector(byte ** ptr, unsigned long sector)
122
{
123
        *(*ptr)++ = sector & 0xff;
124
        sector >>= 8;
125
        *(*ptr)++ = sector & 0xff;
126
        sector >>= 8;
127
        *(*ptr)++ = sector & 0xff;
128
}
129
 
130
unsigned long get_sector(byte ** ptr, mode_type mode)
131
{
132
        unsigned long sector;
133
 
134
        if (mode == forward) {
135
                sector = *(*ptr)++;
136
                sector += *(*ptr)++ << 8;
137
                sector += *(*ptr)++ << 16;
138
        } else {
139
                sector = *--(*ptr) << 16;
140
                sector += *--(*ptr) << 8;
141
                sector += *--(*ptr);
142
        }
143
        return sector;
144
}
145
 
146
void extract_bad_sector_map(byte * buffer)
147
{
148
        TRACE_FUN(8, "extract_bad_sector_map");
149
 
150
        /*  Fill the bad sector map with the contents of buffer.
151
         */
152
        if (format_code == 4) {
153
                /* QIC-3010/3020 and wide QIC-80 tapes no longer have a failed
154
                 * sector log but use this area to extend the bad sector map.
155
                 */
156
                memcpy(bad_sector_map, buffer + 256, sizeof(bad_sector_map));
157
        } else {
158
                /* non-wide QIC-80 tapes have a failed sector log area that
159
                 * mustn't be included in the bad sector map.
160
                 */
161
                memcpy(bad_sector_map, buffer + 256 + FAILED_SECTOR_LOG_SIZE,
162
                       sizeof(bad_sector_map) - FAILED_SECTOR_LOG_SIZE);
163
        }
164
#if 0
165
        /* for testing of bad sector handling at end of tape
166
         */
167
        ((unsigned long *) bad_sector_map)[segments_per_track * tracks_per_tape - 3] = 0x000003e0;
168
        ((unsigned long *) bad_sector_map)[segments_per_track * tracks_per_tape - 2] = 0xff3fffff;
169
        ((unsigned long *) bad_sector_map)[segments_per_track * tracks_per_tape - 1] = 0xffffe000;
170
#endif
171
#if 0
172
        /*  Enable to test bad sector handling
173
         */
174
        ((unsigned long *) bad_sector_map)[30] = 0xfffffffe;
175
        ((unsigned long *) bad_sector_map)[32] = 0x7fffffff;
176
        ((unsigned long *) bad_sector_map)[34] = 0xfffeffff;
177
        ((unsigned long *) bad_sector_map)[36] = 0x55555555;
178
        ((unsigned long *) bad_sector_map)[38] = 0xffffffff;
179
        ((unsigned long *) bad_sector_map)[50] = 0xffff0000;
180
        ((unsigned long *) bad_sector_map)[51] = 0xffffffff;
181
        ((unsigned long *) bad_sector_map)[52] = 0xffffffff;
182
        ((unsigned long *) bad_sector_map)[53] = 0x0000ffff;
183
#endif
184
#if 0
185
        /*  Enable when testing multiple volume tar dumps.
186
         */
187
        for (i = first_data_segment; i <= ftape_last_segment.id - 7; ++i) {
188
                ((unsigned long *) bad_sector_map)[i] = EMPTY_SEGMENT;
189
        }
190
#endif
191
#if 0
192
        /*  Enable when testing bit positions in *_error_map
193
         */
194
        for (i = first_data_segment; i <= ftape_last_segment.id; ++i) {
195
                ((unsigned long *) bad_sector_map)[i] |= 0x00ff00ff;
196
        }
197
#endif
198
        if (tracing > 2) {
199
                unsigned int map;
200
                int good_sectors = 0;
201
                int bad_sectors;
202
                unsigned int total_bad = 0;
203
                int i;
204
 
205
                if (format_code == 4 || format_code == 3) {
206
                        byte *ptr = bad_sector_map;
207
                        unsigned sector;
208
 
209
                        do {
210
                                sector = get_sector(&ptr, forward);
211
                                if (sector != 0) {
212
                                        if (format_code == 4 && sector & 0x800000) {
213
                                                total_bad += SECTORS_PER_SEGMENT - 3;
214
                                                TRACEx1(6, "bad segment at sector: %6d", sector & 0x7fffff);
215
                                        } else {
216
                                                ++total_bad;
217
                                                TRACEx1(6, "bad sector: %6d", sector);
218
                                        }
219
                                }
220
                        } while (sector != 0);
221
                        /*  Display end-of-file marks
222
                         */
223
                        do {
224
                                sector = *((unsigned short *) ptr)++;
225
                                if (sector) {
226
                                        TRACEx2(4, "eof mark: %4d/%2d", sector,
227
                                            *((unsigned short *) ptr)++);
228
                                }
229
                        } while (sector);
230
                } else {
231
                        for (i = first_data_segment;
232
                         i < segments_per_track * tracks_per_tape; ++i) {
233
                                map = ((unsigned long *) bad_sector_map)[i];
234
                                bad_sectors = count_ones(map);
235
                                if (bad_sectors > 0) {
236
                                        TRACEx2(6, "bsm for segment %4d: 0x%08x", i, map);
237
                                        if (bad_sectors > SECTORS_PER_SEGMENT - 3) {
238
                                                bad_sectors = SECTORS_PER_SEGMENT - 3;
239
                                        }
240
                                        total_bad += bad_sectors;
241
                                }
242
                        }
243
                }
244
                good_sectors = ((segments_per_track * tracks_per_tape - first_data_segment)
245
                                * (SECTORS_PER_SEGMENT - 3)) - total_bad;
246
                TRACEx1(3, "%d Kb usable on this tape",
247
                        good_sectors - ftape_last_segment.free);
248
                if (total_bad == 0) {
249
                        TRACE(1, "WARNING: this tape has no bad blocks registered !");
250
                } else {
251
                        TRACEx1(2, "%d bad sectors", total_bad);
252
                }
253
        }
254
        TRACE_EXIT;
255
}
256
 
257
unsigned long cvt2map(int sector)
258
{
259
        return 1 << (((sector & 0x7fffff) - 1) % SECTORS_PER_SEGMENT);
260
}
261
 
262
int cvt2segment(int sector)
263
{
264
        return ((sector & 0x7fffff) - 1) / SECTORS_PER_SEGMENT;
265
}
266
 
267
int forward_seek_entry(int segment_id, byte ** ptr, unsigned long *map)
268
{
269
        byte *tmp_ptr;
270
        unsigned long sector;
271
        int segment;
272
        int count;
273
 
274
        do {
275
                sector = get_sector(ptr, forward);
276
                segment = cvt2segment(sector);
277
        } while (sector != 0 && segment < segment_id);
278
        tmp_ptr = *ptr - 3;     /* point to first sector >= segment_id */
279
        /*  Get all sectors in segment_id
280
         */
281
        if (format_code == 4 && (sector & 0x800000) && segment == segment_id) {
282
                *map = EMPTY_SEGMENT;
283
                count = 32;
284
        } else {
285
                *map = 0;
286
                count = 0;
287
                while (sector != 0 && segment == segment_id) {
288
                        *map |= cvt2map(sector);
289
                        sector = get_sector(ptr, forward);
290
                        segment = cvt2segment(sector);
291
                        ++count;
292
                }
293
        }
294
        *ptr = tmp_ptr;
295
        return count;
296
}
297
 
298
int backwards_seek_entry(int segment_id, byte ** ptr, unsigned long *map)
299
{
300
        unsigned long sector;
301
        int segment;
302
        int count;
303
 
304
        *map = 0;
305
        if (*ptr > bad_sector_map) {
306
                do {
307
                        sector = get_sector(ptr, backward);
308
                        segment = cvt2segment(sector);
309
                } while (*ptr > bad_sector_map && segment > segment_id);
310
                count = 0;
311
                if (segment > segment_id) {
312
                        /*  at start of list, no entry found */
313
                } else if (segment < segment_id) {
314
                        /*  before smaller entry, adjust for overshoot */
315
                        *ptr += 3;
316
                } else {
317
                        /*  get all sectors in segment_id */
318
                        if (format_code == 4 && (sector & 0x800000)) {
319
                                *map = EMPTY_SEGMENT;
320
                                count = 32;
321
                        } else {
322
                                do {
323
                                        *map |= cvt2map(sector);
324
                                        ++count;
325
                                        if (*ptr <= bad_sector_map) {
326
                                                break;
327
                                        }
328
                                        sector = get_sector(ptr, backward);
329
                                        segment = cvt2segment(sector);
330
                                } while (segment == segment_id);
331
                                if (segment < segment_id) {
332
                                        *ptr += 3;
333
                                }
334
                        }
335
                }
336
        } else {
337
                count = 0;
338
        }
339
        return count;
340
}
341
 
342
void put_bad_sector_entry(int segment_id, unsigned long new_map)
343
{
344
        byte *ptr = bad_sector_map;
345
        int count;
346
        int new_count;
347
        unsigned long map;
348
 
349
        if (format_code == 3 || format_code == 4) {
350
                count = forward_seek_entry(segment_id, &ptr, &map);
351
                new_count = count_ones(new_map);
352
                /*  If format code == 4 put empty segment instead of 32 bad sectors.
353
                 */
354
                if (new_count == 32 && format_code == 4) {
355
                        new_count = 1;
356
                }
357
                if (count != new_count) {
358
                        /*  insert (or delete if < 0) new_count - count entries.
359
                         *  Move trailing part of list including terminating 0.
360
                         */
361
                        byte *hi_ptr = ptr;
362
 
363
                        do {
364
                        } while (get_sector(&hi_ptr, forward) != 0);
365
                        memmove(ptr + new_count, ptr + count, hi_ptr - (ptr + count));
366
                }
367
                if (new_count == 1 && new_map == EMPTY_SEGMENT) {
368
                        put_sector(&ptr, 0x800001 + segment_id * SECTORS_PER_SEGMENT);
369
                } else {
370
                        int i = 0;
371
 
372
                        while (new_map) {
373
                                if (new_map & 1) {
374
                                        put_sector(&ptr, 1 + segment_id * SECTORS_PER_SEGMENT + i);
375
                                }
376
                                ++i;
377
                                new_map >>= 1;
378
                        }
379
                }
380
        } else {
381
                ((unsigned long *) bad_sector_map)[segment_id] = new_map;
382
        }
383
        bad_sector_map_changed = 1;
384
}
385
 
386
unsigned long get_bad_sector_entry(int segment_id)
387
{
388
        TRACE_FUN(8, "get_bad_sector_entry");
389
        static unsigned long map = 0;
390
 
391
        if (used_header_segment == -1) {
392
                /*  When reading header segment we'll need a blank map.
393
                 */
394
                map = 0;
395
        } else if (format_code == 3 || format_code == 4) {
396
                /*  Invariants:
397
                 *    map - mask value returned on last call.
398
                 *    ptr - points to first sector greater or equal to
399
                 *          first sector in last_referenced segment.
400
                 *    last_referenced - segment id used in the last call,
401
                 *                      sector and map belong to this id.
402
                 *  This code is designed for sequential access and retries.
403
                 *  For true random access it may have to be redesigned.
404
                 */
405
                static int last_reference = -1;
406
                static byte *ptr = bad_sector_map;
407
 
408
                if (segment_id > last_reference) {
409
                        /*  Skip all sectors before segment_id
410
                         */
411
                        forward_seek_entry(segment_id, &ptr, &map);
412
                } else if (segment_id < last_reference) {
413
                        /*  Skip backwards until begin of buffer or first sector in segment_id
414
                         */
415
                        backwards_seek_entry(segment_id, &ptr, &map);
416
                }               /* segment_id == last_reference : keep map */
417
                last_reference = segment_id;
418
        } else {
419
                map = ((unsigned long *) bad_sector_map)[segment_id];
420
        }
421
        TRACE_EXIT;
422
        return map;
423
}
424
 
425
void ftape_init_bsm(void)
426
{
427
        memset(bad_sector_map, 0, sizeof(bad_sector_map));
428
}

powered by: WebSVN 2.1.0

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