Commit | Line | Data |
---|---|---|
15637ed4 RG |
1 | /* |
2 | * Copyright (c) 1980,1986,1988 Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
5 | * Redistribution and use in source and binary forms, with or without | |
6 | * modification, are permitted provided that the following conditions | |
7 | * are met: | |
8 | * 1. Redistributions of source code must retain the above copyright | |
9 | * notice, this list of conditions and the following disclaimer. | |
10 | * 2. Redistributions in binary form must reproduce the above copyright | |
11 | * notice, this list of conditions and the following disclaimer in the | |
12 | * documentation and/or other materials provided with the distribution. | |
13 | * 3. All advertising materials mentioning features or use of this software | |
14 | * must display the following acknowledgement: | |
15 | * This product includes software developed by the University of | |
16 | * California, Berkeley and its contributors. | |
17 | * 4. Neither the name of the University nor the names of its contributors | |
18 | * may be used to endorse or promote products derived from this software | |
19 | * without specific prior written permission. | |
20 | * | |
21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
31 | * SUCH DAMAGE. | |
32 | */ | |
33 | ||
34 | #ifndef lint | |
35 | char copyright[] = | |
36 | "@(#) Copyright (c) 1980,1986,1988 Regents of the University of California.\n\ | |
37 | All rights reserved.\n"; | |
38 | #endif not lint | |
39 | ||
40 | #ifndef lint | |
41 | static char sccsid[] = "@(#)bad144.c 5.19 (Berkeley) 4/11/91"; | |
42 | #endif not lint | |
43 | ||
44 | /* | |
45 | * bad144 | |
46 | * | |
47 | * This program prints and/or initializes a bad block record for a pack, | |
48 | * in the format used by the DEC standard 144. | |
49 | * It can also add bad sector(s) to the record, moving the sector | |
50 | * replacements as necessary. | |
51 | * | |
52 | * It is preferable to write the bad information with a standard formatter, | |
53 | * but this program will do. | |
54 | * | |
55 | * RP06 sectors are marked as bad by inverting the format bit in the | |
56 | * header; on other drives the valid-sector bit is cleared. | |
57 | */ | |
1148d35e AM |
58 | |
59 | #define DKTYPENAMES | |
60 | ||
15637ed4 RG |
61 | #include <sys/param.h> |
62 | #include <sys/dkbad.h> | |
63 | #include <sys/ioctl.h> | |
64 | #include <ufs/fs.h> | |
65 | #include <sys/file.h> | |
66 | #include <sys/disklabel.h> | |
67 | ||
68 | #include <stdio.h> | |
69 | #include <paths.h> | |
1148d35e | 70 | #include <string.h> |
15637ed4 RG |
71 | |
72 | #define RETRIES 10 /* number of retries on reading old sectors */ | |
73 | #ifdef __386BSD__ | |
74 | #define RAWPART "d" /* disk partition containing badsector tables */ | |
75 | #else | |
76 | #define RAWPART "c" /* disk partition containing badsector tables */ | |
77 | #endif | |
78 | ||
1148d35e | 79 | int fflag, add, copy, verbose, nflag, sflag; |
15637ed4 RG |
80 | int compare(); |
81 | int dups; | |
82 | int badfile = -1; /* copy of badsector table to use, -1 if any */ | |
83 | #define MAXSECSIZE 1024 | |
84 | struct dkbad curbad, oldbad; | |
85 | #define DKBAD_MAGIC 0x4321 | |
86 | ||
1148d35e | 87 | char *buf; |
15637ed4 RG |
88 | char label[BBSIZE]; |
89 | daddr_t size, getold(), badsn(); | |
90 | struct disklabel *dp; | |
91 | char name[BUFSIZ]; | |
92 | char *malloc(); | |
93 | off_t lseek(); | |
1148d35e AM |
94 | int bstart, bend; /* start and ending block numbers */ |
95 | char *p; /* temp dev name pointer */ | |
96 | char devname[BUFSIZ]; | |
97 | ||
98 | #ifdef __386BSD__ | |
99 | static char * parts[] = { | |
100 | "ROOT ", | |
101 | "SWAP ", | |
102 | "386BSD", | |
103 | "DISK ", | |
104 | "DOS? ", | |
105 | "USR2 ", | |
106 | "USR1 ", | |
107 | "USR " | |
108 | }; | |
109 | #endif | |
15637ed4 RG |
110 | |
111 | main(argc, argv) | |
112 | int argc; | |
113 | char *argv[]; | |
114 | { | |
115 | register struct bt_bad *bt; | |
116 | daddr_t sn, bn[126]; | |
1148d35e | 117 | int i, j, f, nbad, new, bad, errs; |
15637ed4 | 118 | |
1148d35e | 119 | setbuf(stdout, NULL); |
15637ed4 RG |
120 | argc--, argv++; |
121 | while (argc > 0 && **argv == '-') { | |
122 | (*argv)++; | |
123 | while (**argv) { | |
124 | switch (**argv) { | |
125 | #if vax | |
126 | case 'f': | |
127 | fflag++; | |
128 | break; | |
129 | #endif | |
130 | case 'a': | |
131 | add++; | |
132 | break; | |
133 | case 'c': | |
134 | copy++; | |
135 | break; | |
136 | case 'v': | |
137 | verbose++; | |
138 | break; | |
139 | case 'n': | |
140 | nflag++; | |
141 | verbose++; | |
142 | break; | |
1148d35e AM |
143 | case 's': /* scan partition */ |
144 | sflag++; | |
145 | verbose++; | |
146 | break; | |
15637ed4 RG |
147 | default: |
148 | if (**argv >= '0' && **argv <= '4') { | |
149 | badfile = **argv - '0'; | |
150 | break; | |
151 | } | |
152 | goto usage; | |
153 | } | |
154 | (*argv)++; | |
155 | } | |
156 | argc--, argv++; | |
157 | } | |
158 | if (argc < 1) { | |
159 | usage: | |
1148d35e AM |
160 | fprintf(stderr, "usage: bad144 [ -f ] disk [ snum [ bn ... ] ]\n"); |
161 | fprintf(stderr, "to read or overwrite bad-sector table, e.g., bad144 hp0\n"); | |
162 | fprintf(stderr, "or bad144 -a [ -f ] [ -c ] disk bn ...\n"); | |
15637ed4 RG |
163 | fprintf(stderr, "where options are:\n"); |
164 | fprintf(stderr, "\t-a add new bad sectors to the table\n"); | |
165 | fprintf(stderr, "\t-f reformat listed sectors as bad\n"); | |
166 | fprintf(stderr, "\t-c copy original sector to replacement\n"); | |
1148d35e | 167 | fprintf(stderr, "\t-s scan partition for bad sectors\n"); |
15637ed4 RG |
168 | exit(1); |
169 | } | |
170 | if (argv[0][0] != '/') | |
1148d35e | 171 | (void)sprintf(name, "%sr%s%s", _PATH_DEV, argv[0], RAWPART); |
15637ed4 RG |
172 | else |
173 | strcpy(name, argv[0]); | |
174 | f = open(name, argc == 1? O_RDONLY : O_RDWR); | |
175 | if (f < 0) | |
176 | Perror(name); | |
1148d35e AM |
177 | p = strrchr(name, '/'); |
178 | strcpy(devname,++p); | |
179 | devname[strlen(p)-1] = '\0'; | |
15637ed4 | 180 | /* obtain label and adjust to fit */ |
1148d35e | 181 | dp = (struct disklabel *)&label; |
15637ed4 RG |
182 | if (ioctl(f, DIOCGDINFO, dp) < 0) |
183 | Perror("ioctl DIOCGDINFO"); | |
15637ed4 RG |
184 | if (dp->d_magic != DISKMAGIC || dp->d_magic2 != DISKMAGIC |
185 | /* dkcksum(lp) != 0 */ ) { | |
186 | fprintf(stderr, "Bad pack magic number (pack is unlabeled)\n"); | |
187 | exit(1); | |
188 | } | |
189 | if (dp->d_secsize > MAXSECSIZE || dp->d_secsize <= 0) { | |
190 | fprintf(stderr, "Disk sector size too large/small (%d)\n", | |
191 | dp->d_secsize); | |
192 | exit(7); | |
193 | } | |
194 | #ifdef __386BSD__ | |
195 | if (dp->d_type == DTYPE_SCSI) { | |
196 | fprintf(stderr, "SCSI disks don't use bad144!\n"); | |
197 | exit(1); | |
198 | } | |
199 | /* are we inside a DOS partition? */ | |
1148d35e AM |
200 | if (verbose) { |
201 | printf("device /dev/%s is a %s disk\n", devname, dktypenames[dp->d_type]); | |
202 | j = dp->d_secpercyl; | |
203 | for (i=0; i < dp->d_npartitions; i++) { | |
204 | if (dp->d_partitions[i].p_size == 0) | |
205 | continue; | |
206 | printf("%s%c %s offset: %7d (%4d), size: %7d (%4d), type = %s\n", | |
207 | devname, 'a'+i, parts[i], dp->d_partitions[i].p_offset, | |
208 | dp->d_partitions[i].p_offset/j, | |
209 | dp->d_partitions[i].p_size, | |
210 | dp->d_partitions[i].p_size/j, | |
211 | fstypenames[dp->d_partitions[i].p_fstype]); | |
212 | } | |
213 | } | |
15637ed4 | 214 | if (dp->d_partitions[0].p_offset) { |
1148d35e AM |
215 | /* |
216 | * yes, rules change. assume bad tables at end of partition C, | |
217 | * which maps all of DOS partition we are within -wfj | |
218 | */ | |
219 | size = dp->d_partitions[2].p_offset + | |
220 | dp->d_partitions[2].p_size; | |
15637ed4 RG |
221 | } else |
222 | #endif | |
1148d35e AM |
223 | size = dp->d_nsectors * dp->d_ntracks * dp->d_ncylinders; |
224 | bstart = 0; | |
225 | if (dp->d_partitions[2].p_size) { | |
226 | bstart = dp->d_partitions[2].p_offset; | |
227 | } | |
228 | /* determine where to stop scanning */ | |
229 | bend = dp->d_partitions[2].p_size + dp->d_partitions[2].p_offset; | |
230 | bend -= (dp->d_nsectors + 126); | |
231 | if (verbose) { | |
232 | printf("secs: %d, tracks: %d, cyl: %d, sec/cyl: %d, start: %d, end: %d\n", | |
233 | dp->d_nsectors, dp->d_ntracks, dp->d_ncylinders, | |
234 | dp->d_secpercyl, bstart, bend); | |
235 | } | |
236 | if (sflag) { /* search for bad sectors */ | |
237 | int curr_sec, tries, n; | |
238 | int spc = dp->d_secpercyl; | |
239 | int ss = dp->d_secsize; | |
240 | int trk = dp->d_nsectors; | |
241 | int step; | |
242 | ||
243 | if (buf == (char *)NULL) { | |
244 | buf = malloc((unsigned)(trk*ss)); | |
245 | if (buf == (char *)NULL) { | |
246 | fprintf(stderr, "Out of memory\n"); | |
247 | exit(20); | |
248 | } | |
249 | } | |
250 | ||
251 | printf("Starting scan of /dev/%sc at cylinder %d\n", devname, bstart/spc); | |
252 | /* seek to start of parition c, we are in d */ | |
253 | for (tries = 0; tries < RETRIES; tries++) { | |
254 | if (lseek(f, bstart * ss, L_SET) < 0) { | |
255 | Perror("lseek"); | |
256 | } else | |
257 | break; | |
258 | } | |
259 | step = trk; | |
260 | for (curr_sec = bstart; curr_sec < bend; curr_sec += step) { | |
261 | int gotone = 0; | |
262 | ||
263 | if (verbose) { | |
264 | if ((curr_sec % spc) == 0) | |
265 | printf("\r%4d(%7d)", | |
266 | curr_sec/spc, curr_sec); | |
267 | } | |
268 | for (tries = 0; tries < RETRIES; tries++) { | |
269 | if (lseek(f, curr_sec * ss, L_SET) < 0) { | |
270 | fprintf(stderr, | |
271 | "\nbad144: can't seek sector, %d\n", | |
272 | curr_sec); | |
273 | gotone = 1; | |
274 | } else | |
275 | break; | |
276 | } | |
277 | if (gotone) { | |
278 | fprintf(stderr, | |
279 | "\nbad144: bad sector (seek), %d\n", | |
280 | curr_sec); | |
281 | step = 1; | |
282 | continue; | |
283 | } | |
284 | if (step == trk) { | |
285 | if ((n = read(f, buf, (ss*trk))) == (ss*trk)) { | |
286 | continue; | |
287 | } | |
288 | } | |
289 | /* switch to single sector reads */ | |
290 | lseek(f, curr_sec * ss, L_SET); | |
291 | step = 1; | |
292 | for (tries = 0; tries < RETRIES; tries++) { | |
293 | if ((n = read(f, buf, ss)) != ss) { | |
294 | fprintf(stderr, | |
295 | "\nbad144: can't read sector, | |
296 | %d\n", curr_sec); | |
297 | gotone = 1; | |
298 | lseek(f, curr_sec * ss, L_SET); | |
299 | } else { | |
300 | if ((curr_sec % trk) == 0) { | |
301 | step = trk; | |
302 | } | |
303 | break; | |
304 | } | |
305 | } | |
306 | if (gotone) { | |
307 | fprintf(stderr, | |
308 | "\nbad144: bad sector (read), %d\n", | |
309 | curr_sec); | |
310 | continue; | |
311 | } | |
312 | } | |
313 | } | |
15637ed4 RG |
314 | argc--; |
315 | argv++; | |
316 | if (argc == 0) { | |
317 | sn = getold(f, &oldbad); | |
1148d35e | 318 | printf("\nbad block information at sector %d in %s:\n", |
15637ed4 | 319 | sn, name); |
7d1221ed | 320 | printf("cartridge serial number: %d(10)\n", oldbad.bt_csn); |
15637ed4 RG |
321 | switch (oldbad.bt_flag) { |
322 | ||
323 | case (u_short)-1: | |
324 | printf("alignment cartridge\n"); | |
325 | break; | |
326 | ||
327 | case DKBAD_MAGIC: | |
328 | break; | |
329 | ||
330 | default: | |
331 | printf("bt_flag=%x(16)?\n", oldbad.bt_flag); | |
332 | break; | |
333 | } | |
334 | bt = oldbad.bt_bad; | |
335 | for (i = 0; i < 126; i++) { | |
336 | bad = (bt->bt_cyl<<16) + bt->bt_trksec; | |
337 | if (bad < 0) | |
338 | break; | |
339 | printf("sn=%d, cn=%d, tn=%d, sn=%d\n", badsn(bt), | |
340 | bt->bt_cyl, bt->bt_trksec>>8, bt->bt_trksec&0xff); | |
341 | bt++; | |
342 | } | |
343 | (void) checkold(&oldbad); | |
344 | exit(0); | |
345 | } | |
346 | if (add) { | |
347 | /* | |
348 | * Read in the old badsector table. | |
349 | * Verify that it makes sense, and the bad sectors | |
350 | * are in order. Copy the old table to the new one. | |
351 | */ | |
352 | (void) getold(f, &oldbad); | |
353 | i = checkold(&oldbad); | |
354 | if (verbose) | |
355 | printf("Had %d bad sectors, adding %d\n", i, argc); | |
356 | if (i + argc > 126) { | |
357 | printf("bad144: not enough room for %d more sectors\n", | |
1148d35e | 358 | argc); |
15637ed4 RG |
359 | printf("limited to 126 by information format\n"); |
360 | exit(1); | |
361 | } | |
362 | curbad = oldbad; | |
363 | } else { | |
364 | curbad.bt_csn = atoi(*argv++); | |
365 | argc--; | |
366 | curbad.bt_mbz = 0; | |
367 | curbad.bt_flag = DKBAD_MAGIC; | |
368 | if (argc > 126) { | |
369 | printf("bad144: too many bad sectors specified\n"); | |
370 | printf("limited to 126 by information format\n"); | |
371 | exit(1); | |
372 | } | |
373 | i = 0; | |
374 | } | |
375 | errs = 0; | |
376 | new = argc; | |
377 | while (argc > 0) { | |
378 | daddr_t sn = atoi(*argv++); | |
379 | argc--; | |
380 | if (sn < 0 || sn >= size) { | |
381 | printf("%d: out of range [0,%d) for disk %s\n", | |
382 | sn, size, dp->d_typename); | |
383 | errs++; | |
384 | continue; | |
385 | } | |
386 | bn[i] = sn; | |
387 | curbad.bt_bad[i].bt_cyl = sn / (dp->d_nsectors*dp->d_ntracks); | |
388 | sn %= (dp->d_nsectors*dp->d_ntracks); | |
389 | curbad.bt_bad[i].bt_trksec = | |
390 | ((sn/dp->d_nsectors) << 8) + (sn%dp->d_nsectors); | |
391 | i++; | |
392 | } | |
393 | if (errs) | |
394 | exit(1); | |
395 | nbad = i; | |
396 | while (i < 126) { | |
397 | curbad.bt_bad[i].bt_trksec = -1; | |
398 | curbad.bt_bad[i].bt_cyl = -1; | |
399 | i++; | |
400 | } | |
401 | if (add) { | |
402 | /* | |
403 | * Sort the new bad sectors into the list. | |
404 | * Then shuffle the replacement sectors so that | |
405 | * the previous bad sectors get the same replacement data. | |
406 | */ | |
407 | qsort((char *)curbad.bt_bad, nbad, sizeof (struct bt_bad), | |
408 | compare); | |
409 | if (dups) { | |
1148d35e | 410 | fprintf(stderr, "bad144: bad sectors have been duplicated; can't add existing sectors\n"); |
15637ed4 RG |
411 | exit(3); |
412 | } | |
413 | shift(f, nbad, nbad-new); | |
414 | } | |
415 | if (badfile == -1) | |
416 | i = 0; | |
417 | else | |
418 | i = badfile * 2; | |
419 | for (; i < 10 && i < dp->d_nsectors; i += 2) { | |
420 | if (lseek(f, dp->d_secsize * (size - dp->d_nsectors + i), | |
1148d35e | 421 | L_SET) < 0) |
15637ed4 RG |
422 | Perror("lseek"); |
423 | if (verbose) | |
424 | printf("write badsect file at %d\n", | |
1148d35e | 425 | size - dp->d_nsectors + i); |
15637ed4 | 426 | if (nflag == 0 && write(f, (caddr_t)&curbad, sizeof(curbad)) != |
1148d35e | 427 | sizeof(curbad)) { |
15637ed4 RG |
428 | char msg[80]; |
429 | (void)sprintf(msg, "bad144: write bad sector file %d", | |
430 | i/2); | |
431 | perror(msg); | |
432 | } | |
433 | if (badfile != -1) | |
434 | break; | |
435 | } | |
436 | #ifdef vax | |
437 | if (nflag == 0 && fflag) | |
438 | for (i = nbad - new; i < nbad; i++) | |
439 | format(f, bn[i]); | |
440 | #endif | |
441 | #ifdef DIOCSBAD | |
442 | if (nflag == 0 && ioctl(f, DIOCSBAD, (caddr_t)&curbad) < 0) | |
443 | fprintf(stderr, | |
444 | "Can't sync bad-sector file; reboot for changes to take effect\n"); | |
445 | #endif | |
446 | if ((dp->d_flags & D_BADSECT) == 0 && nflag == 0) { | |
447 | dp->d_flags |= D_BADSECT; | |
448 | if (ioctl(f, DIOCWDINFO, dp) < 0) { | |
449 | perror("label"); | |
450 | fprintf(stderr, "Can't write disklabel to enable bad secctor handling by the drive\n"); | |
451 | exit(1); | |
452 | } | |
453 | } | |
454 | exit(0); | |
455 | } | |
456 | ||
457 | daddr_t | |
458 | getold(f, bad) | |
459 | struct dkbad *bad; | |
460 | { | |
461 | register int i; | |
462 | daddr_t sn; | |
463 | char msg[80]; | |
464 | ||
465 | if (badfile == -1) | |
466 | i = 0; | |
467 | else | |
468 | i = badfile * 2; | |
469 | for (; i < 10 && i < dp->d_nsectors; i += 2) { | |
470 | sn = size - dp->d_nsectors + i; | |
471 | if (lseek(f, sn * dp->d_secsize, L_SET) < 0) | |
472 | Perror("lseek"); | |
473 | if (read(f, (char *) bad, dp->d_secsize) == dp->d_secsize) { | |
474 | if (i > 0) | |
475 | printf("Using bad-sector file %d\n", i/2); | |
476 | return(sn); | |
477 | } | |
478 | (void)sprintf(msg, "bad144: read bad sector file at sn %d", sn); | |
479 | perror(msg); | |
480 | if (badfile != -1) | |
481 | break; | |
482 | } | |
483 | fprintf(stderr, "bad144: %s: can't read bad block info\n", name); | |
484 | exit(1); | |
485 | /*NOTREACHED*/ | |
486 | } | |
487 | ||
488 | checkold() | |
489 | { | |
490 | register int i; | |
491 | register struct bt_bad *bt; | |
492 | daddr_t sn, lsn; | |
493 | int errors = 0, warned = 0; | |
494 | ||
495 | if (oldbad.bt_flag != DKBAD_MAGIC) { | |
496 | fprintf(stderr, "bad144: %s: bad flag in bad-sector table\n", | |
1148d35e | 497 | name); |
15637ed4 RG |
498 | errors++; |
499 | } | |
500 | if (oldbad.bt_mbz != 0) { | |
501 | fprintf(stderr, "bad144: %s: bad magic number\n", name); | |
502 | errors++; | |
503 | } | |
504 | bt = oldbad.bt_bad; | |
505 | for (i = 0; i < 126; i++, bt++) { | |
506 | if (bt->bt_cyl == 0xffff && bt->bt_trksec == 0xffff) | |
507 | break; | |
508 | if ((bt->bt_cyl >= dp->d_ncylinders) || | |
1148d35e AM |
509 | ((bt->bt_trksec >> 8) >= dp->d_ntracks) || |
510 | ((bt->bt_trksec & 0xff) >= dp->d_nsectors)) { | |
15637ed4 | 511 | fprintf(stderr, |
1148d35e | 512 | "bad144: cyl/trk/sect out of range in existing entry: "); |
15637ed4 | 513 | fprintf(stderr, "sn=%d, cn=%d, tn=%d, sn=%d\n", |
1148d35e AM |
514 | badsn(bt), bt->bt_cyl, bt->bt_trksec>>8, |
515 | bt->bt_trksec & 0xff); | |
15637ed4 RG |
516 | errors++; |
517 | } | |
518 | sn = (bt->bt_cyl * dp->d_ntracks + | |
1148d35e AM |
519 | (bt->bt_trksec >> 8)) * |
520 | dp->d_nsectors + (bt->bt_trksec & 0xff); | |
15637ed4 | 521 | if (i > 0 && sn < lsn && !warned) { |
1148d35e AM |
522 | fprintf(stderr, |
523 | "bad144: bad sector file is out of order\n"); | |
524 | errors++; | |
525 | warned++; | |
15637ed4 RG |
526 | } |
527 | if (i > 0 && sn == lsn) { | |
1148d35e AM |
528 | fprintf(stderr, |
529 | "bad144: bad sector file contains duplicates (sn %d)\n", | |
530 | sn); | |
531 | errors++; | |
15637ed4 RG |
532 | } |
533 | lsn = sn; | |
534 | } | |
535 | if (errors) | |
536 | exit(1); | |
537 | return (i); | |
538 | } | |
539 | ||
540 | /* | |
541 | * Move the bad sector replacements | |
542 | * to make room for the new bad sectors. | |
543 | * new is the new number of bad sectors, old is the previous count. | |
544 | */ | |
545 | shift(f, new, old) | |
546 | { | |
547 | daddr_t repl; | |
548 | ||
549 | /* | |
550 | * First replacement is last sector of second-to-last track. | |
551 | */ | |
552 | repl = size - dp->d_nsectors - 1; | |
553 | new--; old--; | |
554 | while (new >= 0 && new != old) { | |
555 | if (old < 0 || | |
1148d35e | 556 | compare(&curbad.bt_bad[new], &oldbad.bt_bad[old]) > 0) { |
15637ed4 RG |
557 | /* |
558 | * Insert new replacement here-- copy original | |
559 | * sector if requested and possible, | |
560 | * otherwise write a zero block. | |
561 | */ | |
562 | if (!copy || | |
1148d35e | 563 | !blkcopy(f, badsn(&curbad.bt_bad[new]), repl - new)) |
15637ed4 RG |
564 | blkzero(f, repl - new); |
565 | } else { | |
566 | if (blkcopy(f, repl - old, repl - new) == 0) | |
1148d35e AM |
567 | fprintf(stderr, |
568 | "Can't copy replacement sector %d to %d\n", | |
15637ed4 RG |
569 | repl-old, repl-new); |
570 | old--; | |
571 | } | |
572 | new--; | |
573 | } | |
574 | } | |
575 | ||
15637ed4 RG |
576 | /* |
577 | * Copy disk sector s1 to s2. | |
578 | */ | |
579 | blkcopy(f, s1, s2) | |
580 | daddr_t s1, s2; | |
581 | { | |
582 | register tries, n; | |
583 | ||
584 | if (buf == (char *)NULL) { | |
585 | buf = malloc((unsigned)dp->d_secsize); | |
586 | if (buf == (char *)NULL) { | |
587 | fprintf(stderr, "Out of memory\n"); | |
588 | exit(20); | |
589 | } | |
590 | } | |
591 | for (tries = 0; tries < RETRIES; tries++) { | |
592 | if (lseek(f, dp->d_secsize * s1, L_SET) < 0) | |
593 | Perror("lseek"); | |
594 | if ((n = read(f, buf, dp->d_secsize)) == dp->d_secsize) | |
595 | break; | |
596 | } | |
597 | if (n != dp->d_secsize) { | |
598 | fprintf(stderr, "bad144: can't read sector, %d: ", s1); | |
599 | if (n < 0) | |
600 | perror((char *)0); | |
601 | return(0); | |
602 | } | |
603 | if (lseek(f, dp->d_secsize * s2, L_SET) < 0) | |
604 | Perror("lseek"); | |
605 | if (verbose) | |
606 | printf("copying %d to %d\n", s1, s2); | |
607 | if (nflag == 0 && write(f, buf, dp->d_secsize) != dp->d_secsize) { | |
608 | fprintf(stderr, | |
609 | "bad144: can't write replacement sector, %d: ", s2); | |
610 | perror((char *)0); | |
611 | return(0); | |
612 | } | |
613 | return(1); | |
614 | } | |
615 | ||
616 | char *zbuf; | |
617 | ||
618 | blkzero(f, sn) | |
619 | daddr_t sn; | |
620 | { | |
621 | ||
622 | if (zbuf == (char *)NULL) { | |
623 | zbuf = malloc((unsigned)dp->d_secsize); | |
624 | if (zbuf == (char *)NULL) { | |
625 | fprintf(stderr, "Out of memory\n"); | |
626 | exit(20); | |
627 | } | |
628 | } | |
629 | if (lseek(f, dp->d_secsize * sn, L_SET) < 0) | |
630 | Perror("lseek"); | |
631 | if (verbose) | |
632 | printf("zeroing %d\n", sn); | |
633 | if (nflag == 0 && write(f, zbuf, dp->d_secsize) != dp->d_secsize) { | |
634 | fprintf(stderr, | |
635 | "bad144: can't write replacement sector, %d: ", sn); | |
636 | perror((char *)0); | |
637 | } | |
638 | } | |
639 | ||
640 | compare(b1, b2) | |
641 | register struct bt_bad *b1, *b2; | |
642 | { | |
643 | if (b1->bt_cyl > b2->bt_cyl) | |
644 | return(1); | |
645 | if (b1->bt_cyl < b2->bt_cyl) | |
646 | return(-1); | |
647 | if (b1->bt_trksec == b2->bt_trksec) | |
648 | dups++; | |
649 | return (b1->bt_trksec - b2->bt_trksec); | |
650 | } | |
651 | ||
652 | daddr_t | |
653 | badsn(bt) | |
654 | register struct bt_bad *bt; | |
655 | { | |
656 | return ((bt->bt_cyl*dp->d_ntracks + (bt->bt_trksec>>8)) * dp->d_nsectors | |
1148d35e | 657 | + (bt->bt_trksec&0xff)); |
15637ed4 RG |
658 | } |
659 | ||
660 | #ifdef vax | |
661 | ||
662 | struct rp06hdr { | |
663 | short h_cyl; | |
664 | short h_trksec; | |
665 | short h_key1; | |
666 | short h_key2; | |
667 | char h_data[512]; | |
668 | #define RP06_FMT 010000 /* 1 == 16 bit, 0 == 18 bit */ | |
669 | }; | |
670 | ||
671 | /* | |
672 | * Most massbus and unibus drives | |
673 | * have headers of this form | |
674 | */ | |
675 | struct hpuphdr { | |
676 | u_short hpup_cyl; | |
677 | u_char hpup_sect; | |
678 | u_char hpup_track; | |
679 | char hpup_data[512]; | |
680 | #define HPUP_OKSECT 0xc000 /* this normally means sector is good */ | |
681 | #define HPUP_16BIT 0x1000 /* 1 == 16 bit format */ | |
682 | }; | |
683 | int rp06format(), hpupformat(); | |
684 | ||
685 | struct formats { | |
686 | char *f_name; /* disk name */ | |
687 | int f_bufsize; /* size of sector + header */ | |
688 | int f_bic; /* value to bic in hpup_cyl */ | |
689 | int (*f_routine)(); /* routine for special handling */ | |
690 | } formats[] = { | |
691 | { "rp06", sizeof (struct rp06hdr), RP06_FMT, rp06format }, | |
692 | { "eagle", sizeof (struct hpuphdr), HPUP_OKSECT, hpupformat }, | |
693 | { "capricorn", sizeof (struct hpuphdr), HPUP_OKSECT, hpupformat }, | |
694 | { "rm03", sizeof (struct hpuphdr), HPUP_OKSECT, hpupformat }, | |
695 | { "rm05", sizeof (struct hpuphdr), HPUP_OKSECT, hpupformat }, | |
696 | { "9300", sizeof (struct hpuphdr), HPUP_OKSECT, hpupformat }, | |
697 | { "9766", sizeof (struct hpuphdr), HPUP_OKSECT, hpupformat }, | |
698 | { 0, 0, 0, 0 } | |
699 | }; | |
700 | ||
701 | /*ARGSUSED*/ | |
702 | hpupformat(fp, dp, blk, buf, count) | |
703 | struct formats *fp; | |
704 | struct disklabel *dp; | |
705 | daddr_t blk; | |
706 | char *buf; | |
707 | int count; | |
708 | { | |
709 | struct hpuphdr *hdr = (struct hpuphdr *)buf; | |
710 | int sect; | |
711 | ||
712 | if (count < sizeof(struct hpuphdr)) { | |
713 | hdr->hpup_cyl = (HPUP_OKSECT | HPUP_16BIT) | | |
1148d35e | 714 | (blk / (dp->d_nsectors * dp->d_ntracks)); |
15637ed4 RG |
715 | sect = blk % (dp->d_nsectors * dp->d_ntracks); |
716 | hdr->hpup_track = (u_char)(sect / dp->d_nsectors); | |
717 | hdr->hpup_sect = (u_char)(sect % dp->d_nsectors); | |
718 | } | |
719 | return (0); | |
720 | } | |
721 | ||
722 | /*ARGSUSED*/ | |
723 | rp06format(fp, dp, blk, buf, count) | |
724 | struct formats *fp; | |
725 | struct disklabel *dp; | |
726 | daddr_t blk; | |
727 | char *buf; | |
728 | int count; | |
729 | { | |
730 | ||
731 | if (count < sizeof(struct rp06hdr)) { | |
732 | fprintf(stderr, "Can't read header on blk %d, can't reformat\n", | |
1148d35e | 733 | blk); |
15637ed4 RG |
734 | return (-1); |
735 | } | |
736 | return (0); | |
737 | } | |
738 | ||
739 | format(fd, blk) | |
740 | int fd; | |
741 | daddr_t blk; | |
742 | { | |
743 | register struct formats *fp; | |
744 | static char *buf; | |
745 | static char bufsize; | |
746 | struct format_op fop; | |
747 | int n; | |
748 | ||
749 | for (fp = formats; fp->f_name; fp++) | |
750 | if (strcmp(dp->d_typename, fp->f_name) == 0) | |
751 | break; | |
752 | if (fp->f_name == 0) { | |
753 | fprintf(stderr, "bad144: don't know how to format %s disks\n", | |
754 | dp->d_typename); | |
755 | exit(2); | |
756 | } | |
757 | if (buf && bufsize < fp->f_bufsize) { | |
758 | free(buf); | |
759 | buf = NULL; | |
760 | } | |
761 | if (buf == NULL) | |
762 | buf = malloc((unsigned)fp->f_bufsize); | |
763 | if (buf == NULL) { | |
764 | fprintf(stderr, "bad144: can't allocate sector buffer\n"); | |
765 | exit(3); | |
766 | } | |
767 | bufsize = fp->f_bufsize; | |
768 | /* | |
769 | * Here we do the actual formatting. All we really | |
770 | * do is rewrite the sector header and flag the bad sector | |
771 | * according to the format table description. If a special | |
772 | * purpose format routine is specified, we allow it to | |
773 | * process the sector as well. | |
774 | */ | |
775 | if (verbose) | |
776 | printf("format blk %d\n", blk); | |
777 | bzero((char *)&fop, sizeof(fop)); | |
778 | fop.df_buf = buf; | |
779 | fop.df_count = fp->f_bufsize; | |
780 | fop.df_startblk = blk; | |
781 | bzero(buf, fp->f_bufsize); | |
782 | if (ioctl(fd, DIOCRFORMAT, &fop) < 0) | |
783 | perror("bad144: read format"); | |
784 | if (fp->f_routine && | |
1148d35e | 785 | (*fp->f_routine)(fp, dp, blk, buf, fop.df_count) != 0) |
15637ed4 RG |
786 | return; |
787 | if (fp->f_bic) { | |
788 | struct hpuphdr *xp = (struct hpuphdr *)buf; | |
789 | ||
790 | xp->hpup_cyl &= ~fp->f_bic; | |
791 | } | |
792 | if (nflag) | |
793 | return; | |
794 | bzero((char *)&fop, sizeof(fop)); | |
795 | fop.df_buf = buf; | |
796 | fop.df_count = fp->f_bufsize; | |
797 | fop.df_startblk = blk; | |
798 | if (ioctl(fd, DIOCWFORMAT, &fop) < 0) | |
799 | Perror("write format"); | |
800 | if (fop.df_count != fp->f_bufsize) { | |
801 | char msg[80]; | |
802 | (void)sprintf(msg, "bad144: write format %d", blk); | |
803 | perror(msg); | |
804 | } | |
805 | } | |
806 | #endif | |
807 | ||
808 | Perror(op) | |
809 | char *op; | |
810 | { | |
811 | ||
812 | fprintf(stderr, "bad144: "); perror(op); | |
813 | exit(4); | |
814 | } |