Commit | Line | Data |
---|---|---|
6cb1d6d5 | 1 | #ifndef lint |
d2b6f994 | 2 | static 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 |
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]; | |
52ff80b5 BJ |
34 | |
35 | main(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 |
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); | |
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 | ||
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)); | |
52ff80b5 | 366 | } |
ace59b28 SL |
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 | }; | |
6cb1d6d5 SL |
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 | }; | |
ace59b28 SL |
387 | |
388 | struct 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 | 404 | format(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 |
456 | Perror(op) |
457 | char *op; | |
ace59b28 SL |
458 | { |
459 | ||
6cb1d6d5 SL |
460 | fprintf(stderr, "bad144: "); perror(op); |
461 | exit(4); | |
ace59b28 | 462 | } |