1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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
38
39
40
41
42static __u8 *bad_sector_map;
43static SectorCount *bsm_hash_ptr;
44
45typedef enum {
46 forward, backward
47} mode_type;
48
49#if 0
50
51
52
53void 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;
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
98
99
100__u8 * ftape_find_end_of_bsm_list(__u8 * address)
101{
102 __u8 *ptr = address + FT_HEADER_END;
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
114static 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
123static 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
135
136
137
138 return (GET4(ptr, 0) & 0x00ffffff);
139#endif
140}
141
142static void bsm_debug_fake(void)
143{
144
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
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
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
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
194static 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
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 {
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
253void ftape_extract_bad_sector_map(__u8 * buffer)
254{
255 TRACE_FUN(ft_t_any);
256
257
258
259 if (ft_format_code == fmt_var || ft_format_code == fmt_big) {
260
261
262
263 bad_sector_map = &buffer[FT_HEADER_END];
264 } else {
265
266
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
284static inline SectorMap cvt2map(unsigned int sector)
285{
286 return 1 << (((sector & 0x7fffff) - 1) % FT_SECTORS_PER_SEGMENT);
287}
288
289static inline int cvt2segment(unsigned int sector)
290{
291 return ((sector & 0x7fffff) - 1) / FT_SECTORS_PER_SEGMENT;
292}
293
294static 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) --;
306
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
329static int backwards_seek_entry(int segment_id,
330 SectorCount **ptr,
331 SectorMap *map)
332{
333 unsigned int sector;
334 int segment;
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) {
345 *map = 0;
346 return 0;
347 } else if (segment < segment_id) {
348
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 {
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
376void 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
390
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
402
403
404
405 SectorCount *hi_ptr = ptr;
406
407 do {
408 } while (get_sector(hi_ptr++) != 0);
409
410
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
440SectorMap ftape_get_bad_sector_entry(int segment_id)
441{
442 if (ft_used_header_segment == -1) {
443
444
445 return 0;
446 } else if (bsm_hash_ptr != NULL) {
447
448
449
450
451
452
453
454
455
456 static int last_reference = -1;
457 static SectorMap map;
458
459 if (segment_id > last_reference) {
460
461
462 forward_seek_entry(segment_id, &bsm_hash_ptr, &map);
463 } else if (segment_id < last_reference) {
464
465
466
467 backwards_seek_entry(segment_id, &bsm_hash_ptr, &map);
468 }
469 last_reference = segment_id;
470 return map;
471 } else {
472 return ((SectorMap *) bad_sector_map)[segment_id];
473 }
474}
475
476
477
478
479void ftape_init_bsm(void)
480{
481 bad_sector_map = NULL;
482 bsm_hash_ptr = NULL;
483}
484