1 #ifndef lint
2 static char sccsid[] = "@(#)maps.c 1.8 (Berkeley/CCI) 06/24/90";
3 #endif
4
5
6 #include "vdfmt.h"
7
8
9 /*
10 **
11 */
12
align_buf(buf,sync)13 boolean align_buf(buf, sync)
14 unsigned long *buf;
15 unsigned long sync;
16 {
17 register int i, shift;
18
19 /* find shift amount */
20 for(shift=0; shift < 32; shift++) {
21 if((*buf >> shift ) == sync) {
22 for(i=(512/sizeof(long))-1; i >= 0; i--) {
23 *(buf+i+1) |= *(buf+i) << (32 - shift);
24 *(buf+i) = *(buf+i) >> shift;
25 }
26 return true;
27 }
28 }
29 return false;
30 }
31
32
33 /*
34 ** Looks for two maps in a row that are the same.
35 */
36
37 boolean
read_map(flags)38 read_map(flags)
39 short flags;
40 {
41 register int trk, i;
42 register bs_map *map;
43 dskadr dskaddr;
44
45 dskaddr.cylinder = (lab->d_ncylinders - 1) | flags;
46 for(trk=0; trk < lab->d_ntracks; trk++) {
47 dskaddr.track = trk;
48 dskaddr.sector = 0;
49 if(access_dsk((char *)map_space, &dskaddr, VDOP_RD,
50 lab->d_nsectors, 1) & VDERR_HARD)
51 continue;
52 map = &norm_bad_map;
53 /*
54 * If this doesn't look like a new-style map,
55 * but (as an old-style map) bs_count and bs_max are sensible,
56 * munge pointer to prepend fields missing in old map.
57 */
58 if (map->bs_magic != BSMAGIC &&
59 map->bs_cksum <= MAX_FLAWMAP(bytes_trk) /* bs_count */
60 && map->bs_id <= MAX_FLAWMAP(bytes_trk)) /* bs_max */
61 map = &offset_bad_map;
62 if (trk > 0 &&
63 bcmp((char *)map_space, (char *)save, bytes_trk) == 0 &&
64 map->bs_count <= MAX_FLAWMAP(bytes_trk)) {
65 for (i=0; i < map->bs_count; i++) {
66 if (map->list[i].bs_cyl >=
67 lab->d_ncylinders)
68 break;
69 if (map->list[i].bs_trk >=
70 lab->d_ntracks)
71 break;
72 if (map->list[i].bs_offset >=
73 lab->d_traksize)
74 break;
75 }
76 if (i == map->bs_count) {
77 bad_map = map;
78 load_free_table();
79 return true;
80 }
81 }
82 bcopy((char *)map_space, (char *)save, bytes_trk);
83 }
84 map = &norm_bad_map;
85 bad_map = map;
86 bzero((char *)map, bytes_trk);
87 map->bs_magic = BSMAGIC;
88 map->bs_id = 0;
89 map->bs_max = MAX_FLAWS;
90 return false;
91 }
92
93
94 /*
95 **
96 */
97
read_bad_sector_map()98 boolean read_bad_sector_map()
99 {
100 dskadr dskaddr;
101
102 dskaddr.cylinder = lab->d_ncylinders - 1;
103 dskaddr.track = 0;
104 dskaddr.sector = 0;
105 offset_bad_map.bs_magic = BSMAGIC;
106 offset_bad_map.bs_cksum = 0;
107 bad_map = &norm_bad_map;
108 /* start with nothing in map */
109 bzero(map_space, bytes_trk);
110 bad_map->bs_magic = BSMAGIC;
111 bad_map->bs_id = 0;
112 bad_map->bs_max = MAX_FLAWS;
113 if (C_INFO->type == VDTYPE_SMDE) {
114 access_dsk((char *)save, &dskaddr, VDOP_RDRAW, 1, 1);
115 if (align_buf((unsigned long *)save, CDCSYNC) == true) {
116 read_flaw_map();
117 return (false);
118 } else if (read_map(NRM) == true) {
119 return (true);
120 } else {
121 get_smde_relocations();
122 return false;
123 }
124 } else {
125 if (read_map(WPT) == true)
126 return (true);
127 else {
128 get_relocations_the_hard_way();
129 return (false);
130 }
131 }
132 }
133
134
135 /*
136 **
137 */
138
get_relocations_the_hard_way()139 get_relocations_the_hard_way()
140 {
141 register int cyl, trk;
142 register int status;
143 dskadr dskaddr;
144
145 dskaddr.sector = 0;
146 /* scan each sector to see if it is relocated and take note if it is */
147 for(cyl=0; cyl < lab->d_ncylinders - NUMSYS; cyl++) {
148 dskaddr.cylinder = cyl;
149 for(trk=0; trk < lab->d_ntracks; trk++) {
150 dskaddr.track = trk;
151 status=access_dsk((char *)scratch, &dskaddr,
152 VDOP_RD, lab->d_nsectors, 1);
153 if(status & DCBS_ATA)
154 get_track_relocations(dskaddr);
155 }
156 }
157 load_free_table();
158 }
159
160
161 /*
162 **
163 */
164
get_track_relocations(dskaddr)165 get_track_relocations(dskaddr)
166 dskadr dskaddr;
167 {
168 register int status;
169 bs_entry temp;
170 fmt_err error;
171
172 for(dskaddr.sector=0; dskaddr.sector < lab->d_nsectors; dskaddr.sector++) {
173 status = access_dsk((char *)scratch, &dskaddr, VDOP_RD, 1, 1);
174 if(status & DCBS_ATA) {
175 error.err_adr = dskaddr;
176 error.err_stat = DATA_ERROR;
177 (*C_INFO->code_pos)(&error, &temp);
178 temp.bs_how = operator;
179 add_flaw(&temp);
180 }
181 }
182 }
183
184
185 /*
186 **
187 */
188
remove_user_relocations(entry)189 remove_user_relocations(entry)
190 bs_entry *entry;
191 {
192 register int i, j;
193 fmt_err temp;
194 fmt_err error;
195 register bs_entry *ptr;
196
197 (*C_INFO->decode_pos)(entry, &error);
198 ptr = bad_map->list;
199 for(i=0; i < bad_map->bs_count; i++) {
200 if (ptr->bs_cyl != entry->bs_cyl ||
201 ptr->bs_trk != entry->bs_trk)
202 continue;
203 (*C_INFO->decode_pos)(ptr, &temp);
204 if((ptr->bs_how != flaw_map) &&
205 (temp.err_adr.cylinder == error.err_adr.cylinder) &&
206 (temp.err_adr.track == error.err_adr.track) &&
207 (temp.err_adr.sector == error.err_adr.sector)) {
208 if(temp.err_stat & HEADER_ERROR)
209 remove_track(&temp, ptr);
210 else
211 remove_sector(&temp, ptr);
212 for(j=i+1; j < bad_map->bs_count; j++)
213 bad_map->list[j-1] = bad_map->list[j];
214 bad_map->bs_count--;
215 return;
216 }
217 ptr++;
218 }
219 indent();
220 print("Sector %d is not in bad sector map!\n",
221 to_sector(error.err_adr));
222 exdent(1);
223 }
224
clear_relocations(reformat)225 clear_relocations(reformat)
226 boolean reformat;
227 {
228 fmt_err temp;
229 register bs_entry *ptr1, *ptr2, *end;
230 int oldsub = cur.substate;
231
232 cur.substate = sub_rel;
233 ptr1 = bad_map->list;
234 ptr2 = bad_map->list;
235 end = &bad_map->list[bad_map->bs_count];
236 for (; ptr1 < end; ptr1++) {
237 if (ptr1->bs_how != flaw_map) {
238 if (reformat == true) {
239 (*C_INFO->decode_pos)(ptr1, &temp);
240 if(temp.err_stat & HEADER_ERROR)
241 remove_track(&temp, ptr1);
242 else
243 remove_sector(&temp, ptr1);
244 }
245 bad_map->bs_count--;
246 } else {
247 if (ptr1 != ptr2)
248 *ptr2 = *ptr1;
249 ptr2++;
250 }
251 }
252 cur.substate = oldsub;
253 }
254
255
256 /*
257 **
258 */
259
remove_sector(error,entry)260 remove_sector(error, entry)
261 fmt_err *error;
262 bs_entry *entry;
263 {
264 format_sectors(&error->err_adr, &error->err_adr, NRM, 1);
265 format_sectors(&entry->bs_alt, &entry->bs_alt, NRM, 1);
266 }
267
268
269 /*
270 **
271 */
272
remove_track(error,entry)273 remove_track(error, entry)
274 fmt_err *error;
275 bs_entry *entry;
276 {
277 format_sectors(&error->err_adr,&error->err_adr,NRM,(long)lab->d_nsectors);
278 format_sectors(&entry->bs_alt,&entry->bs_alt,NRM,(long)lab->d_nsectors);
279 }
280
281
282 /*
283 **
284 */
285
write_bad_sector_map()286 write_bad_sector_map()
287 {
288 register int trk, sec;
289 dskadr dskaddr;
290
291 bad_map->bs_magic = BSMAGIC;
292 bad_map->bs_id = 0;
293 dskaddr.cylinder = (lab->d_ncylinders - NUMMAP);
294 for(trk=0; trk < lab->d_ntracks; trk++) {
295 for(sec = 0; sec < lab->d_nsectors; sec++) {
296 bcopy((char *)bad_map + (sec * lab->d_secsize),
297 (char *)scratch, lab->d_secsize);
298 dskaddr.track = trk;
299 dskaddr.sector = sec;
300 format_sectors(&dskaddr, &dskaddr, WPT, 1);
301 }
302 }
303 }
304
305
306 /*
307 **
308 */
309
zero_bad_sector_map()310 zero_bad_sector_map()
311 {
312 bs_map *bm = bad_map;
313 register int i;
314 dskadr zero;
315
316 zero.cylinder = 0;
317 zero.track = 0;
318 zero.sector = 0;
319 for(i=0; i < bm->bs_count; i++)
320 bm->list[i].bs_alt = zero;
321 load_free_table();
322 }
323
324
325 /*
326 **
327 */
328
read_flaw_map()329 read_flaw_map()
330 {
331 register int cyl, trk;
332 dskadr dskaddr;
333 flaw buffer;
334
335 dskaddr.sector = 0;
336 for (cyl=0; cyl < lab->d_ncylinders; cyl++) {
337 dskaddr.cylinder = cyl;
338 for (trk=0; trk < lab->d_ntracks; trk++) {
339 dskaddr.track = trk;
340 access_dsk(&buffer, &dskaddr, VDOP_RDRAW, 1, 1);
341 if(align_buf(&buffer, CDCSYNC) == true) {
342 add_flaw_entries(&buffer);
343 continue;
344 }
345 }
346 }
347 load_free_table();
348 }
349
350
351 /*
352 **
353 */
354
get_smde_relocations()355 get_smde_relocations()
356 {
357 register int cyl, trk, sec;
358 smde_hdr buffer;
359 dskadr dskaddr;
360 fmt_err bad;
361 bs_entry temp;
362 boolean bad_track;
363
364 /* Read any old drive relocations */
365 for(cyl=0; cyl < NUMREL; cyl++) {
366 dskaddr.cylinder = lab->d_ncylinders - NUMSYS + cyl;
367 for(trk=0; trk < lab->d_ntracks; trk++) {
368 dskaddr.track = trk;
369 bad_track = true;
370 for(sec=0; sec < lab->d_nsectors; sec++) {
371 dskaddr.sector = sec;
372 access_dsk(&buffer, &dskaddr, VDOP_RDRAW, 1, 1);
373 if(align_buf(&buffer, SMDE1SYNC) == false) {
374 bad_track = false;
375 break;
376 }
377 }
378 if(bad_track == true) {
379 dskaddr.sector = 0;
380 bad.err_adr.cylinder = buffer.alt_cyl;
381 bad.err_adr.track = buffer.alt_trk;
382 bad.err_adr.sector = 0;
383 bad.err_stat = HEADER_ERROR;
384 (*C_INFO->code_pos)(&bad, &temp);
385 temp.bs_alt = dskaddr;
386 temp.bs_how = scanning;
387 add_flaw(&temp);
388 continue;
389 }
390 for(sec=0; sec < lab->d_nsectors; sec++) {
391 dskaddr.sector = sec;
392 access_dsk(&buffer, &dskaddr, VDOP_RDRAW, 1, 1);
393 if(align_buf(&buffer, SMDE1SYNC) == true) {
394 bad.err_adr.cylinder = buffer.alt_cyl;
395 bad.err_adr.track = buffer.alt_trk;
396 bad.err_adr.sector = buffer.alt_sec;
397 bad.err_stat = DATA_ERROR;
398 (*C_INFO->code_pos)(&bad, &temp);
399 temp.bs_alt = dskaddr;
400 temp.bs_how = scanning;
401 add_flaw(&temp);
402 }
403 }
404 }
405 }
406 load_free_table();
407 }
408
409
410 /*
411 **
412 */
413
add_flaw_entries(buffer)414 add_flaw_entries(buffer)
415 flaw *buffer;
416 {
417 register int i;
418 bs_entry temp;
419
420 temp.bs_cyl = buffer->flaw_cyl & 0x7fff; /* clear off bad track bit */
421 temp.bs_trk = buffer->flaw_trk;
422 for(i=0; i < 4; i++) {
423 if(buffer->flaw_pos[i].flaw_length != 0) {
424 temp.bs_offset = buffer->flaw_pos[i].flaw_offset;
425 temp.bs_length = buffer->flaw_pos[i].flaw_length;
426 temp.bs_alt.cylinder = 0;
427 temp.bs_alt.track = 0;
428 temp.bs_alt.sector = 0;
429 temp.bs_how = flaw_map;
430 add_flaw(&temp);
431 }
432 }
433 }
434
435
cmp_entry(a,b)436 cmp_entry(a, b)
437 bs_entry *a;
438 bs_entry *b;
439 {
440 if(a->bs_cyl == b->bs_cyl) {
441 if(a->bs_trk == b->bs_trk) {
442 if(a->bs_offset == b->bs_offset)
443 return 0;
444 else if(a->bs_offset < b->bs_offset)
445 return -1;
446 }
447 else if(a->bs_trk < b->bs_trk)
448 return -1;
449 }
450 else if(a->bs_cyl < b->bs_cyl)
451 return -1;
452 return 1;
453 }
454
455
456 /*
457 * Add flaw to map.
458 * Return value:
459 * 1 OK
460 * 0 sector was in map
461 * -1 failure
462 */
add_flaw(entry)463 add_flaw(entry)
464 bs_entry *entry;
465 {
466 extern int cmp_entry();
467 bs_map *bm = bad_map;
468 register int i;
469
470 if(bm->bs_count > MAX_FLAWS)
471 return (-1);
472 if (entry->bs_cyl >= lab->d_ncylinders ||
473 entry->bs_trk >= lab->d_ntracks ||
474 entry->bs_offset >= lab->d_traksize)
475 return (-1);
476 for(i=0; i < bm->bs_count; i++) {
477 if(((bm->list[i].bs_cyl == entry->bs_cyl)) &&
478 (bm->list[i].bs_trk == entry->bs_trk) &&
479 (bm->list[i].bs_offset == entry->bs_offset)) {
480 if((int)bm->list[i].bs_how > (int)entry->bs_how)
481 bm->list[i].bs_how = entry->bs_how;
482 return (0);
483 }
484 }
485 bm->list[i] = *entry;
486 bm->list[i].bs_alt.cylinder = 0;
487 bm->list[i].bs_alt.track = 0;
488 bm->list[i].bs_alt.sector = 0;
489 bm->bs_count++;
490 qsort((char *)&(bm->list[0]), (unsigned)bm->bs_count,
491 sizeof(bs_entry), cmp_entry);
492 return (1);
493 }
494
495
496 /*
497 ** Is_in_map checks to see if a block is known to be bad already.
498 */
499
is_in_map(dskaddr)500 boolean is_in_map(dskaddr)
501 dskadr *dskaddr;
502 {
503 register int i;
504 fmt_err temp;
505
506 for(i=0; i < bad_map->bs_count; i++) {
507 (*C_INFO->decode_pos)(&bad_map->list[i], &temp);
508 if((temp.err_adr.cylinder == dskaddr->cylinder) &&
509 (temp.err_adr.track == dskaddr->track) &&
510 (temp.err_adr.sector == dskaddr->sector)) {
511 return true;
512 }
513 }
514 return false;
515 }
516
517
518 /*
519 **
520 */
521
print_bad_sector_list()522 print_bad_sector_list()
523 {
524 register int i;
525 fmt_err errloc;
526 register bs_entry *bad;
527
528 if(bad_map->bs_magic != BSMAGIC)
529 print("Bad-sector map magic number wrong! (%x != %x)\n",
530 bad_map->bs_magic, BSMAGIC);
531 if(bad_map->bs_count == 0) {
532 print("There are no bad sectors in bad sector map.\n");
533 return;
534 }
535 print("The following %d sector%s known to be bad:\n",
536 bad_map->bs_count, (bad_map->bs_count == 1) ? " is" : "s are");
537 exdent(0);
538 for(i=0, bad = bad_map->list; i < bad_map->bs_count; i++, bad++) {
539 (*C_INFO->decode_pos)(bad, &errloc);
540 print("%c %d cn %d tn %d sn %d pos %d len %d ",
541 errloc.err_stat & HEADER_ERROR ? 'T' : 'S',
542 to_sector(errloc.err_adr),
543 bad->bs_cyl,
544 bad->bs_trk,
545 errloc.err_adr.sector,
546 bad->bs_offset,
547 bad->bs_length);
548 if (bad->bs_how == flaw_map)
549 printf("(flawmap) ");
550 else if (bad->bs_how == scanning)
551 printf("(verify) ");
552 else
553 printf("(operator) ");
554 if((bad->bs_alt.cylinder != 0) || (bad->bs_alt.track != 0) ||
555 (bad->bs_alt.sector != 0)) {
556 printf("-> ");
557 printf("cn %d tn %d sn %d", bad->bs_alt.cylinder,
558 bad->bs_alt.track, bad->bs_alt.sector);
559 }
560 printf("\n");
561 }
562 }
563
564
565 /*
566 ** load_free_table checks each block in the bad block relocation area
567 ** to see if it is used. If it is, the free relocation block table is updated.
568 */
569
load_free_table()570 load_free_table()
571 {
572 register int i, j;
573 fmt_err temp;
574
575 /* Clear free table before starting */
576 for(i = 0; i < (lab->d_ntracks * NUMREL); i++) {
577 for(j=0; j < lab->d_nsectors; j++)
578 free_tbl[i][j].free_status = NOTALLOCATED;
579 }
580 for(i=0; i < bad_map->bs_count; i++)
581 if((bad_map->list[i].bs_alt.cylinder != 0) ||
582 (bad_map->list[i].bs_alt.track != 0) ||
583 (bad_map->list[i].bs_alt.sector != 0)) {
584 (*C_INFO->decode_pos)(&bad_map->list[i], &temp);
585 allocate(&(bad_map->list[i].bs_alt), temp.err_stat);
586 }
587 }
588
589
590 /*
591 ** allocate marks a replacement sector as used.
592 */
593
allocate(dskaddr,status)594 allocate(dskaddr, status)
595 dskadr *dskaddr;
596 long status;
597 {
598 register int trk, sec;
599
600 trk = dskaddr->cylinder - (lab->d_ncylinders - NUMSYS);
601 if((trk < 0) || (trk >= NUMREL))
602 return;
603 trk *= lab->d_ntracks;
604 trk += dskaddr->track;
605 if(status & HEADER_ERROR)
606 for(sec=0; sec < lab->d_nsectors; sec++)
607 free_tbl[trk][sec].free_status = ALLOCATED;
608 else
609 free_tbl[trk][dskaddr->sector].free_status = ALLOCATED;
610 }
611
612
613 /*
614 **
615 */
616
mapping_collision(entry)617 boolean mapping_collision(entry)
618 bs_entry *entry;
619 {
620 register int trk, sec;
621 fmt_err temp;
622
623 trk = entry->bs_cyl - (lab->d_ncylinders - NUMSYS);
624 if((trk < 0) || (trk >= NUMREL))
625 return false;
626 trk *= lab->d_ntracks;
627 trk += entry->bs_trk;
628 (*C_INFO->decode_pos)(entry, &temp);
629 /* if this relocation should take up the whole track */
630 if(temp.err_stat & HEADER_ERROR) {
631 for(sec=0; sec < lab->d_nsectors; sec++)
632 if(free_tbl[trk][sec].free_status == ALLOCATED)
633 return true;
634 }
635 /* else just check the current sector */
636 else {
637 if(free_tbl[trk][temp.err_adr.sector].free_status == ALLOCATED)
638 return true;
639 }
640 return false;
641 }
642
643
644 /*
645 **
646 */
647
report_collision()648 report_collision()
649 {
650 indent();
651 print("Sector resides in relocation area");
652 printf("but it has a sector mapped to it already.\n");
653 print("Please reformat disk with 0 patterns to eliminate problem.\n");
654 exdent(1);
655 }
656
657
658 /*
659 **
660 */
661
add_user_relocations(entry)662 add_user_relocations(entry)
663 bs_entry *entry;
664 {
665 fmt_err error;
666
667 (*C_INFO->decode_pos)(entry, &error);
668 if(is_in_map(&error.err_adr) == false) {
669 if(mapping_collision(entry) == true)
670 report_collision();
671 entry->bs_how = operator;
672 add_flaw(entry);
673 }
674 else {
675 indent();
676 print("Sector %d is already mapped out!\n",
677 to_sector(error.err_adr));
678 exdent(1);
679 }
680 }
681
682
683 /*
684 ** New_location allocates a replacement block given a bad block address.
685 ** The algorithm is fairly simple; it simply searches for the first
686 ** free sector that has the same sector number of the bad sector. If no sector
687 ** is found then the drive should be considered bad because of a microcode bug
688 ** in the controller that forces us to use the same sector number as the bad
689 ** sector for relocation purposes. Using different tracks and cylinders is ok
690 ** of course.
691 */
692
new_location(entry)693 dskadr *new_location(entry)
694 bs_entry *entry;
695 {
696 register int i, sec;
697 static fmt_err temp;
698 static dskadr newaddr;
699
700 newaddr.cylinder = 0;
701 newaddr.track = 0;
702 newaddr.sector = 0;
703 (*C_INFO->decode_pos)(entry, &temp);
704 /* If it is ouside of the user's data area */
705 if(entry->bs_cyl >= lab->d_ncylinders-NUMSYS) {
706 /* if it is in the relocation area */
707 if(entry->bs_cyl < (lab->d_ncylinders - NUMMAP - NUMMNT)) {
708 /* mark space as allocated */
709 allocate(&temp.err_adr, temp.err_stat);
710 return &temp.err_adr;
711 }
712 /* if it is in the map area forget about it */
713 if(entry->bs_cyl != (lab->d_ncylinders - NUMMAP - NUMMNT))
714 return &temp.err_adr;
715 /* otherwise treat maintainence cylinder normally */
716 }
717 if(temp.err_stat & (HEADER_ERROR)) {
718 for(i = 0; i < (lab->d_ntracks * NUMREL); i++) {
719 for(sec=0; sec < lab->d_nsectors; sec++) {
720 if(free_tbl[i][sec].free_status == ALLOCATED)
721 break;
722 }
723 if(sec == lab->d_nsectors) {
724 for(sec = 0; sec < lab->d_nsectors; sec++)
725 free_tbl[i][sec].free_status=ALLOCATED;
726 newaddr.cylinder = i / lab->d_ntracks +
727 (lab->d_ncylinders - NUMSYS);
728 newaddr.track = i % lab->d_ntracks;
729 break;
730 }
731 }
732 }
733 else if(C_INFO->type == VDTYPE_VDDC) {
734 for(i = 0; i < (lab->d_ntracks * NUMREL); i++) {
735 if(free_tbl[i][temp.err_adr.sector].free_status !=
736 ALLOCATED) {
737 free_tbl[i][temp.err_adr.sector].free_status =
738 ALLOCATED;
739 newaddr.cylinder = i / lab->d_ntracks +
740 (lab->d_ncylinders - NUMSYS);
741 newaddr.track = i % lab->d_ntracks;
742 newaddr.sector = temp.err_adr.sector;
743 break;
744 }
745 }
746 }
747 else {
748 for(i = 0; i < (lab->d_ntracks * NUMREL); i++) {
749 for(sec=0; sec < lab->d_nsectors; sec++)
750 if(free_tbl[i][sec].free_status != ALLOCATED)
751 break;
752 if(sec < lab->d_nsectors) {
753 free_tbl[i][sec].free_status = ALLOCATED;
754 newaddr.cylinder = i / lab->d_ntracks +
755 (lab->d_ncylinders - NUMSYS);
756 newaddr.track = i % lab->d_ntracks;
757 newaddr.sector = sec;
758 break;
759 }
760 }
761 }
762 return &newaddr;
763 }
764