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