made minimum granularity of vertical movement a parameter read from DESC file
[unix-history] / usr / src / usr.sbin / bad144 / bad144.c
CommitLineData
6cb1d6d5 1#ifndef lint
d2b6f994 2static char *sccsid = "@(#)bad144.c 4.8 (Berkeley) 84/03/22";
6cb1d6d5 3#endif
52ff80b5
BJ
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.
d2b6f994
MK
10 * It can also add bad sector(s) to the record, moving the sector
11 * replacements as necessary.
52ff80b5
BJ
12 *
13 * It is preferable to write the bad information with a standard formatter,
d2b6f994 14 * but this program will do.
ace59b28 15 *
6cb1d6d5 16 * RP06 sectors are marked as bad by inverting the format bit in the
d2b6f994 17 * header; on other drives the valid-sector bit is cleared.
52ff80b5
BJ
18 */
19#include <sys/types.h>
20#include <sys/dkbad.h>
ace59b28 21#include <sys/ioctl.h>
6cb1d6d5 22#include <sys/file.h>
ace59b28 23#include <machine/dkio.h>
347d81fa 24
52ff80b5 25#include <stdio.h>
347d81fa 26#include <disktab.h>
52ff80b5 27
d2b6f994
MK
28int fflag, add, copy, verbose;
29int compare();
30struct dkbad dkbad, oldbad;
31daddr_t size, getold(), badsn();
32struct disktab *dp;
33char name[BUFSIZ];
52ff80b5
BJ
34
35main(argc, argv)
36 int argc;
6cb1d6d5 37 char *argv[];
52ff80b5 38{
52ff80b5 39 register struct bt_bad *bt;
d2b6f994
MK
40 daddr_t sn, bn[126];
41 int i, f, nbad, new, bad, errs;
52ff80b5
BJ
42
43 argc--, argv++;
d2b6f994
MK
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 }
ace59b28 63 argc--, argv++;
ace59b28 64 }
52ff80b5 65 if (argc < 2) {
ace59b28
SL
66 fprintf(stderr,
67 "usage: bad144 [ -f ] type disk [ snum [ bn ... ] ]\n");
d2b6f994
MK
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");
347d81fa
SL
76 exit(1);
77 }
78 dp = getdiskbyname(argv[0]);
79 if (dp == NULL) {
80 fprintf(stderr, "%s: unknown disk type\n", argv[0]);
52ff80b5
BJ
81 exit(1);
82 }
d2b6f994
MK
83 if (argv[1][0] != '/')
84 sprintf(name, "/dev/r%sc", argv[1]);
85 else
86 strcpy(name, argv[1]);
52ff80b5
BJ
87 argc -= 2;
88 argv += 2;
347d81fa 89 size = dp->d_nsectors * dp->d_ntracks * dp->d_ncylinders;
52ff80b5 90 if (argc == 0) {
6cb1d6d5
SL
91 f = open(name, O_RDONLY);
92 if (f < 0)
93 Perror(name);
d2b6f994 94 sn = getold(f, &dkbad);
95317c9f 95 printf("bad block information at sector %d in %s:\n",
d2b6f994
MK
96 sn, name);
97 printf("cartridge serial number: %d(10)\n", dkbad.bt_csn);
52ff80b5 98 switch (dkbad.bt_flag) {
347d81fa 99
52ff80b5
BJ
100 case -1:
101 printf("alignment cartridge\n");
102 break;
347d81fa 103
52ff80b5
BJ
104 case 0:
105 break;
347d81fa 106
52ff80b5
BJ
107 default:
108 printf("bt_flag=%x(16)?\n", dkbad.bt_flag);
109 break;
110 }
52ff80b5 111 bt = dkbad.bt_bad;
d2b6f994 112 for (i = 0; i < 126; i++) {
52ff80b5
BJ
113 bad = (bt->bt_cyl<<16) + bt->bt_trksec;
114 if (bad < 0)
115 break;
d2b6f994 116 printf("sn=%d, cn=%d, tn=%d, sn=%d\n", badsn(bt),
52ff80b5
BJ
117 bt->bt_cyl, bt->bt_trksec>>8, bt->bt_trksec&0xff);
118 bt++;
119 }
6cb1d6d5 120 exit(0);
52ff80b5 121 }
d2b6f994 122 f = open(name, (fflag || add)? O_RDWR: O_WRONLY);
6cb1d6d5
SL
123 if (f < 0)
124 Perror(name);
d2b6f994
MK
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;
52ff80b5
BJ
152 }
153 errs = 0;
d2b6f994 154 new = argc;
52ff80b5 155 while (argc > 0) {
d2b6f994 156 daddr_t sn = atoi(*argv++);
52ff80b5 157 argc--;
347d81fa 158 if (sn < 0 || sn >= size) {
52ff80b5 159 printf("%d: out of range [0,%d) for %s\n",
347d81fa 160 sn, size, dp->d_name);
52ff80b5 161 errs++;
d2b6f994 162 continue;
52ff80b5 163 }
d2b6f994 164 bn[i] = sn;
347d81fa
SL
165 dkbad.bt_bad[i].bt_cyl = sn / (dp->d_nsectors*dp->d_ntracks);
166 sn %= (dp->d_nsectors*dp->d_ntracks);
52ff80b5 167 dkbad.bt_bad[i].bt_trksec =
347d81fa 168 ((sn/dp->d_nsectors) << 8) + (sn%dp->d_nsectors);
52ff80b5
BJ
169 i++;
170 }
d2b6f994
MK
171 if (errs)
172 exit(1);
173 nbad = i;
52ff80b5
BJ
174 while (i < 126) {
175 dkbad.bt_bad[i].bt_trksec = -1;
176 dkbad.bt_bad[i].bt_cyl = -1;
177 i++;
178 }
d2b6f994
MK
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 }
ace59b28 201 if (fflag)
d2b6f994
MK
202 for (i = 0; i < new; i++)
203 format(f, bn[i]);
204 exit(0);
205}
ace59b28 206
d2b6f994
MK
207daddr_t
208getold(f, bad)
209struct 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);
ace59b28 223 }
d2b6f994
MK
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
232checkold()
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 */
275shift(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 */
309blkcopy(f, s1, s2)
310daddr_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
333char zbuf[512];
334
335blkzero(f, sn)
336daddr_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
350compare(b1, b2)
351register 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
360daddr_t
361badsn(bt)
362register 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));
52ff80b5 366}
ace59b28
SL
367
368struct 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};
6cb1d6d5
SL
376
377/*
378 * Most massbus and unibus drives
379 * have headers of this form
380 */
381struct 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};
ace59b28
SL
387
388struct formats {
389 char *f_name; /* disk name */
390 int f_bufsize; /* size of sector + header */
6cb1d6d5 391 int f_bic; /* value to bic in hpup_cyl */
ace59b28
SL
392 int (*f_routine)(); /* routine for special handling */
393} formats[] = {
6cb1d6d5
SL
394 { "rp06", sizeof (struct rp06hdr), RP06_FMT, 0 },
395 { "eagle", sizeof (struct hpuphdr), HPUP_OKSECT, 0 },
396 { "capricorn", sizeof (struct hpuphdr), HPUP_OKSECT, 0 },
d2b6f994
MK
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 },
6cb1d6d5 401 { 0, 0, 0, 0 }
ace59b28
SL
402};
403
d2b6f994 404format(fd, blk)
ace59b28 405 int fd;
ace59b28
SL
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 */
6cb1d6d5
SL
431 if (lseek(fd, (long)blk * 512, L_SET) < 0)
432 Perror("lseek");
d2b6f994
MK
433 if (verbose)
434 printf("format blk %d\n", blk);
6cb1d6d5
SL
435 if (ioctl(fd, DKIOCHDR, 0) < 0)
436 Perror("ioctl");
95317c9f 437 read(fd, buf, fp->f_bufsize);
6cb1d6d5
SL
438 if (fp->f_bic) {
439 struct hpuphdr *xp = (struct hpuphdr *)buf;
440
441 xp->hpup_cyl &= ~fp->f_bic;
442 }
ace59b28
SL
443 if (fp->f_routine)
444 (*fp->f_routine)(fp, dp, blk, buf);
6cb1d6d5
SL
445 if (lseek(fd, (long)blk * 512, L_SET) < 0)
446 Perror("lseek");
447 if (ioctl(fd, DKIOCHDR, 0) < 0)
448 Perror("ioctl");
d2b6f994
MK
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 }
ace59b28
SL
454}
455
6cb1d6d5
SL
456Perror(op)
457 char *op;
ace59b28
SL
458{
459
6cb1d6d5
SL
460 fprintf(stderr, "bad144: "); perror(op);
461 exit(4);
ace59b28 462}