xref: /original-bsd/usr.sbin/bad144/bad144.c (revision aba77441)
1 /*
2  * Copyright (c) 1980 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 char copyright[] =
9 "@(#) Copyright (c) 1980 Regents of the University of California.\n\
10  All rights reserved.\n";
11 #endif not lint
12 
13 #ifndef lint
14 static char sccsid[] = "@(#)bad144.c	5.1 (Berkeley) 06/06/85";
15 #endif not lint
16 
17 /*
18  * bad144
19  *
20  * This program prints and/or initializes a bad block record for a pack,
21  * in the format used by the DEC standard 144.
22  * It can also add bad sector(s) to the record, moving the sector
23  * replacements as necessary.
24  *
25  * It is preferable to write the bad information with a standard formatter,
26  * but this program will do.
27  *
28  * RP06 sectors are marked as bad by inverting the format bit in the
29  * header; on other drives the valid-sector bit is cleared.
30  */
31 #include <sys/types.h>
32 #include <sys/dkbad.h>
33 #include <sys/ioctl.h>
34 #include <sys/file.h>
35 #include <machine/dkio.h>
36 
37 #include <stdio.h>
38 #include <disktab.h>
39 
40 int	fflag, add, copy, verbose;
41 int	compare();
42 struct	dkbad dkbad, oldbad;
43 daddr_t	size, getold(), badsn();
44 struct	disktab *dp;
45 char	name[BUFSIZ];
46 
47 main(argc, argv)
48 	int argc;
49 	char *argv[];
50 {
51 	register struct bt_bad *bt;
52 	daddr_t	sn, bn[126];
53 	int i, f, nbad, new, bad, errs;
54 
55 	argc--, argv++;
56 	while (argc > 0 && **argv == '-') {
57 		(*argv)++;
58 		while (**argv) {
59 			switch (**argv) {
60 			    case 'f':
61 				fflag++;
62 				break;
63 			    case 'a':
64 				add++;
65 				break;
66 			    case 'c':
67 				copy++;
68 				break;
69 			    case 'v':
70 				verbose++;
71 				break;
72 			}
73 			(*argv)++;
74 		}
75 		argc--, argv++;
76 	}
77 	if (argc < 2) {
78 		fprintf(stderr,
79 		  "usage: bad144 [ -f ] type disk [ snum [ bn ... ] ]\n");
80 		fprintf(stderr,
81 	      "to read or overwrite bad-sector table, e.g.: bad144 rk07 hk0\n");
82 		fprintf(stderr,
83 		  "or bad144 -a [ -f ] [ -c ] type disk  bn ...\n");
84 		fprintf(stderr, "where options are:\n");
85 		fprintf(stderr, "\t-a  add new bad sectors to the table\n");
86 		fprintf(stderr, "\t-f  reformat listed sectors as bad\n");
87 		fprintf(stderr, "\t-c  copy original sector to replacement\n");
88 		exit(1);
89 	}
90 	dp = getdiskbyname(argv[0]);
91 	if (dp == NULL) {
92 		fprintf(stderr, "%s: unknown disk type\n", argv[0]);
93 		exit(1);
94 	}
95 	if (argv[1][0] != '/')
96 		sprintf(name, "/dev/r%sc", argv[1]);
97 	else
98 		strcpy(name, argv[1]);
99 	argc -= 2;
100 	argv += 2;
101 	size = dp->d_nsectors * dp->d_ntracks * dp->d_ncylinders;
102 	if (argc == 0) {
103 		f = open(name, O_RDONLY);
104 		if (f < 0)
105 			Perror(name);
106 		sn = getold(f, &dkbad);
107 		printf("bad block information at sector %d in %s:\n",
108 		    sn, name);
109 		printf("cartridge serial number: %d(10)\n", dkbad.bt_csn);
110 		switch (dkbad.bt_flag) {
111 
112 		case -1:
113 			printf("alignment cartridge\n");
114 			break;
115 
116 		case 0:
117 			break;
118 
119 		default:
120 			printf("bt_flag=%x(16)?\n", dkbad.bt_flag);
121 			break;
122 		}
123 		bt = dkbad.bt_bad;
124 		for (i = 0; i < 126; i++) {
125 			bad = (bt->bt_cyl<<16) + bt->bt_trksec;
126 			if (bad < 0)
127 				break;
128 			printf("sn=%d, cn=%d, tn=%d, sn=%d\n", badsn(bt),
129 			    bt->bt_cyl, bt->bt_trksec>>8, bt->bt_trksec&0xff);
130 			bt++;
131 		}
132 		exit(0);
133 	}
134 	f = open(name, (fflag || add)? O_RDWR: O_WRONLY);
135 	if (f < 0)
136 		Perror(name);
137 	if (add) {
138 		/*
139 		 * Read in the old badsector table.
140 		 * Verify that it makes sense, and the bad sectors
141 		 * are in order.  Copy the old table to the new one.
142 		 */
143 		(void) getold(f, &oldbad);
144 		i = checkold();
145 		if (verbose)
146 			printf("Had %d bad sectors\n", i);
147 		if (i + argc > 126) {
148 			printf("bad144: not enough room for %d more sectors\n",
149 				argc);
150 			printf("limited to 126 by information format\n");
151 			exit(1);
152 		}
153 		dkbad = oldbad;
154 	} else {
155 		dkbad.bt_csn = atoi(*argv++);
156 		argc--;
157 		dkbad.bt_mbz = 0;
158 		if (argc > 126) {
159 			printf("bad144: too many bad sectors specified\n");
160 			printf("limited to 126 by information format\n");
161 			exit(1);
162 		}
163 		i = 0;
164 	}
165 	errs = 0;
166 	new = argc;
167 	while (argc > 0) {
168 		daddr_t sn = atoi(*argv++);
169 		argc--;
170 		if (sn < 0 || sn >= size) {
171 			printf("%d: out of range [0,%d) for %s\n",
172 			    sn, size, dp->d_name);
173 			errs++;
174 			continue;
175 		}
176 		bn[i] = sn;
177 		dkbad.bt_bad[i].bt_cyl = sn / (dp->d_nsectors*dp->d_ntracks);
178 		sn %= (dp->d_nsectors*dp->d_ntracks);
179 		dkbad.bt_bad[i].bt_trksec =
180 		    ((sn/dp->d_nsectors) << 8) + (sn%dp->d_nsectors);
181 		i++;
182 	}
183 	if (errs)
184 		exit(1);
185 	nbad = i;
186 	while (i < 126) {
187 		dkbad.bt_bad[i].bt_trksec = -1;
188 		dkbad.bt_bad[i].bt_cyl = -1;
189 		i++;
190 	}
191 	if (add) {
192 		/*
193 		 * Sort the new bad sectors into the list.
194 		 * Then shuffle the replacement sectors so that
195 		 * the previous bad sectors get the same replacement data.
196 		 */
197 		qsort(dkbad.bt_bad, nbad, sizeof (struct bt_bad), compare);
198 		shift(f, nbad, nbad-new);
199 	}
200 	for (i = 0; i < 10; i += 2) {
201 		if (lseek(f, dp->d_secsize * (size - dp->d_nsectors + i),
202 		    L_SET) < 0)
203 			Perror("lseek");
204 		if (verbose)
205 			printf("write badsect file at %d\n",
206 				size - dp->d_nsectors + i);
207 		if (write(f, (caddr_t)&dkbad, sizeof dkbad) != sizeof dkbad) {
208 			char msg[80];
209 			sprintf(msg, "bad144: write bad sector file %d", i/2);
210 			perror(msg);
211 		}
212 	}
213 	if (fflag)
214 		for (i = 0; i < new; i++)
215 			format(f, bn[i]);
216 	exit(0);
217 }
218 
219 daddr_t
220 getold(f, bad)
221 struct dkbad *bad;
222 {
223 	register int i;
224 	daddr_t sn;
225 	char msg[80];
226 
227 	for (i = 0; i < 10; i += 2) {
228 		sn = size - dp->d_nsectors + i;
229 		if (lseek(f, sn * dp->d_secsize, L_SET) < 0)
230 			Perror("lseek");
231 		if (read(f, bad, sizeof (*bad)) == sizeof (*bad)) {
232 			if (i > 0)
233 				printf("Using bad-sector file %d\n", i/2);
234 			return(sn);
235 		}
236 		sprintf(msg, "bad144: read bad sector file at sn %d", sn);
237 		perror(msg);
238 	}
239 	fprintf(stderr,
240 	    "bad144: %s: can't read bad block info\n", name);
241 	exit(1);
242 }
243 
244 checkold()
245 {
246 	register int i;
247 	register struct bt_bad *bt;
248 	daddr_t sn, lsn;
249 
250 	if (oldbad.bt_flag != 0) {
251 		fprintf(stderr, "bad144: %s: bad flag in bad-sector table\n",
252 			name);
253 		exit(1);
254 	}
255 	if (oldbad.bt_mbz != 0) {
256 		fprintf(stderr, "bad144: %s: bad magic number\n", name);
257 		exit(1);
258 	}
259 	lsn = 0;
260 	bt = oldbad.bt_bad;
261 	for (i = 0; i < 126; i++, bt++) {
262 		if (bt->bt_cyl == -1 && bt->bt_trksec == -1)
263 			break;
264 		if ((bt->bt_cyl >= dp->d_ncylinders) ||
265 		    ((bt->bt_trksec >> 8) >= dp->d_ntracks) ||
266 		    ((bt->bt_trksec & 0xff) >= dp->d_nsectors)) {
267 			fprintf(stderr, "bad144: cyl/sect/trk out of range\n");
268 			exit(1);
269 		}
270 		sn = (bt->bt_cyl * dp->d_ntracks +
271 		    (bt->bt_trksec >> 8)) *
272 		    dp->d_nsectors + (bt->bt_trksec & 0xff);
273 		if (sn < lsn) {
274 		    fprintf(stderr, "bad144: bad sector file out of order\n");
275 		    exit(1);
276 		}
277 		lsn = sn;
278 	}
279 	return i;
280 }
281 
282 /*
283  * Move the bad sector replacements
284  * to make room for the new bad sectors.
285  * new is the new number of bad sectors, old is the previous count.
286  */
287 shift(f, new, old)
288 {
289 	daddr_t repl;
290 
291 	/*
292 	 * First replacement is last sector of second-to-last track.
293 	 */
294 	repl = size - dp->d_nsectors - 1;
295 	new--; old--;
296 	while (new >= 0 && new != old) {
297 		if (old < 0 ||
298 		    compare(&dkbad.bt_bad[new], &oldbad.bt_bad[old]) > 0) {
299 			/*
300 			 * Insert new replacement here-- copy original
301 			 * sector if requested and possible,
302 			 * otherwise write a zero block.
303 			 */
304 			if (!copy ||
305 			    !blkcopy(f, badsn(&dkbad.bt_bad[new]), repl - new))
306 				blkzero(f, repl - new);
307 		} else {
308 			if (blkcopy(f, repl - old, repl - new) == 0)
309 			    fprintf(stderr,
310 				"Can't copy replacement sector %d to %d\n",
311 				repl-old, repl-new);
312 			old--;
313 		}
314 		new--;
315 	}
316 }
317 
318 /*
319  *  Copy disk sector s1 to s2.
320  */
321 blkcopy(f, s1, s2)
322 daddr_t s1, s2;
323 {
324 	char buf[512];
325 
326 	if (lseek(f, dp->d_secsize * s1, L_SET) < 0)
327 		Perror("lseek");
328 	if (read(f, buf, sizeof (buf)) != sizeof (buf)) {
329 		if (verbose)
330 			fprintf(stderr, "bad144: can't read sector, %d\n", s1);
331 		return(0);
332 	}
333 	if (lseek(f, dp->d_secsize * s2, L_SET) < 0)
334 		Perror("lseek");
335 	if (verbose)
336 		printf("copying %d to %d\n", s1, s2);
337 	if (write(f, buf, sizeof (buf)) != sizeof (buf)) {
338 		fprintf(stderr,
339 		    "bad144: can't write replacement sector, %d\n", s2);
340 		return(0);
341 	}
342 	return(1);
343 }
344 
345 char zbuf[512];
346 
347 blkzero(f, sn)
348 daddr_t sn;
349 {
350 
351 	if (lseek(f, dp->d_secsize * sn, L_SET) < 0)
352 		Perror("lseek");
353 	if (verbose)
354 		printf("zeroing %d\n", sn);
355 	if (write(f, zbuf, sizeof (zbuf)) != sizeof (zbuf)) {
356 		fprintf(stderr,
357 		    "bad144: can't write replacement sector, %d\n", sn);
358 		exit(1);
359 	}
360 }
361 
362 compare(b1, b2)
363 register struct bt_bad *b1, *b2;
364 {
365 	if (b1->bt_cyl > b2->bt_cyl)
366 		return(1);
367 	if (b1->bt_cyl < b2->bt_cyl)
368 		return(-1);
369 	return (b2->bt_trksec - b1->bt_trksec);
370 }
371 
372 daddr_t
373 badsn(bt)
374 register struct bt_bad *bt;
375 {
376 	return ((bt->bt_cyl*dp->d_ntracks + (bt->bt_trksec>>8)) * dp->d_nsectors
377 		+ (bt->bt_trksec&0xff));
378 }
379 
380 struct rp06hdr {
381 	short	h_cyl;
382 	short	h_trksec;
383 	short	h_key1;
384 	short	h_key2;
385 	char	h_data[512];
386 #define	RP06_FMT	010000		/* 1 == 16 bit, 0 == 18 bit */
387 };
388 
389 /*
390  * Most massbus and unibus drives
391  * have headers of this form
392  */
393 struct hpuphdr {
394 	u_short	hpup_cyl;
395 	u_short hpup_trksec;
396 	char	hpup_data[512];
397 #define	HPUP_OKSECT	0xc000		/* this normally means sector is good */
398 };
399 
400 struct	formats {
401 	char	*f_name;		/* disk name */
402 	int	f_bufsize;		/* size of sector + header */
403 	int	f_bic;			/* value to bic in hpup_cyl */
404 	int	(*f_routine)();		/* routine for special handling */
405 } formats[] = {
406 	{ "rp06",	sizeof (struct rp06hdr),	RP06_FMT,	0 },
407 	{ "eagle",	sizeof (struct hpuphdr),	HPUP_OKSECT,	0 },
408 	{ "capricorn",	sizeof (struct hpuphdr),	HPUP_OKSECT,	0 },
409 	{ "rm03",	sizeof (struct hpuphdr),	HPUP_OKSECT,	0 },
410 	{ "rm05",	sizeof (struct hpuphdr),	HPUP_OKSECT,	0 },
411 	{ "9300",	sizeof (struct hpuphdr),	HPUP_OKSECT,	0 },
412 	{ "9766",	sizeof (struct hpuphdr),	HPUP_OKSECT,	0 },
413 	{ 0, 0, 0, 0 }
414 };
415 
416 format(fd, blk)
417 	int fd;
418 	daddr_t blk;
419 {
420 	register struct formats *fp;
421 	char *buf, *malloc();
422 
423 	for (fp = formats; fp->f_name; fp++)
424 		if (strcmp(dp->d_name, fp->f_name) == 0)
425 			break;
426 	if (fp->f_name == 0) {
427 		fprintf(stderr, "bad144: don't know how to format %s disks\n",
428 			dp->d_name);
429 		exit(2);
430 	}
431 	buf = malloc(fp->f_bufsize);
432 	if (buf == NULL) {
433 		fprintf(stderr, "bad144: can't allocate sector buffer\n");
434 		exit(3);
435 	}
436 	/*
437 	 * Here we do the actual formatting.  All we really
438 	 * do is rewrite the sector header and flag the bad sector
439 	 * according to the format table description.  If a special
440 	 * purpose format routine is specified, we allow it to
441 	 * process the sector as well.
442 	 */
443 	if (lseek(fd, (long)blk * 512, L_SET) < 0)
444 		Perror("lseek");
445 	if (verbose)
446 		printf("format blk %d\n", blk);
447 	if (ioctl(fd, DKIOCHDR, 0) < 0)
448 		Perror("ioctl");
449 	read(fd, buf, fp->f_bufsize);
450 	if (fp->f_bic) {
451 		struct hpuphdr *xp = (struct hpuphdr *)buf;
452 
453 		xp->hpup_cyl &= ~fp->f_bic;
454 	}
455 	if (fp->f_routine)
456 		(*fp->f_routine)(fp, dp, blk, buf);
457 	if (lseek(fd, (long)blk * 512, L_SET) < 0)
458 		Perror("lseek");
459 	if (ioctl(fd, DKIOCHDR, 0) < 0)
460 		Perror("ioctl");
461 	if (write(fd, buf, fp->f_bufsize) != fp->f_bufsize) {
462 		char msg[80];
463 		sprintf(msg, "bad144: write format %d", blk);
464 		perror(msg);
465 	}
466 }
467 
468 Perror(op)
469 	char *op;
470 {
471 
472 	fprintf(stderr, "bad144: "); perror(op);
473 	exit(4);
474 }
475