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