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