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