#ifndef lint static char *sccsid = "@(#)bad144.c 4.7 (Berkeley) 83/07/27"; #endif /* * bad144 * * This program prints and/or initializes a bad block record for a pack, * in the format used by the DEC standard 144. * * BUGS: * Only reads/writes the first of the bad block record (sector 0 * of the last track of the disk); in fact, there are copies * of the information in the first 5 even numbered sectors of this * track, but UNIX uses only the first, and we don't bother with the * others. * * It is preferable to write the bad information with a standard formatter, * but this program will do in a pinch, e.g. if the bad information is * accidentally wiped out this is a much faster way of restoring it than * reformatting. * * RP06 sectors are marked as bad by inverting the format bit in the * header; on other drives the BSE bit is set. */ #include <sys/types.h> #include <sys/dkbad.h> #include <sys/ioctl.h> #include <sys/file.h> #include <machine/dkio.h> #include <stdio.h> #include <disktab.h> int fflag; struct dkbad dkbad; main(argc, argv) int argc; char *argv[]; { register struct bt_bad *bt; register struct disktab *dp; char name[BUFSIZ]; int size, i, f, bad, oldbad, errs; argc--, argv++; if (argc > 0 && strcmp(*argv, "-f") == 0) { argc--, argv++; fflag++; } if (argc < 2) { fprintf(stderr, "usage: bad144 [ -f ] type disk [ snum [ bn ... ] ]\n"); fprintf(stderr, "e.g.: bad144 rk07 hk0\n"); exit(1); } dp = getdiskbyname(argv[0]); if (dp == NULL) { fprintf(stderr, "%s: unknown disk type\n", argv[0]); exit(1); } sprintf(name, "/dev/r%sc", argv[1]); argc -= 2; argv += 2; size = dp->d_nsectors * dp->d_ntracks * dp->d_ncylinders; if (argc == 0) { f = open(name, O_RDONLY); if (f < 0) Perror(name); if (lseek(f, dp->d_secsize*(size-dp->d_nsectors), L_SET) < 0) Perror("lseek"); printf("bad block information at sector %d in %s:\n", tell(f)/512, name); if (read(f, &dkbad, sizeof (struct dkbad)) != sizeof (struct dkbad)) { fprintf("bad144: %s: can't read bad block info\n"); exit(1); } printf("cartidge serial number: %d(10)\n", dkbad.bt_csn); switch (dkbad.bt_flag) { case -1: printf("alignment cartridge\n"); break; case 0: break; default: printf("bt_flag=%x(16)?\n", dkbad.bt_flag); break; } oldbad = 0; bt = dkbad.bt_bad; for (i = 0; i < 128; i++) { bad = (bt->bt_cyl<<16) + bt->bt_trksec; if (bad < 0) break; printf("sn=%d, cn=%d, tn=%d, sn=%d\n", (bt->bt_cyl*dp->d_ntracks + (bt->bt_trksec>>8)) * dp->d_nsectors + (bt->bt_trksec&0xff), bt->bt_cyl, bt->bt_trksec>>8, bt->bt_trksec&0xff); bt++; } exit(0); } f = open(name, 1 + fflag); if (f < 0) Perror(name); dkbad.bt_csn = atoi(*argv++); argc--; dkbad.bt_mbz = 0; if (argc > 126) { printf("bad144: too many bad sectors specified\n"); printf("limited to 126 by information format\n"); exit(1); } errs = 0; i = 0; while (argc > 0) { int sn = atoi(*argv++); argc--; if (sn < 0 || sn >= size) { printf("%d: out of range [0,%d) for %s\n", sn, size, dp->d_name); errs++; } dkbad.bt_bad[i].bt_cyl = sn / (dp->d_nsectors*dp->d_ntracks); sn %= (dp->d_nsectors*dp->d_ntracks); dkbad.bt_bad[i].bt_trksec = ((sn/dp->d_nsectors) << 8) + (sn%dp->d_nsectors); i++; } while (i < 126) { dkbad.bt_bad[i].bt_trksec = -1; dkbad.bt_bad[i].bt_cyl = -1; i++; } if (errs) exit(1); if (lseek(f, dp->d_secsize * (size - dp->d_nsectors), L_SET) < 0) Perror("lseek"); if (write(f, (caddr_t)&dkbad, sizeof (dkbad)) != sizeof (dkbad)) Perror(name); if (fflag) for (i = 0, bt = dkbad.bt_bad; i < 126; i++, bt++) { daddr_t bn; bad = (bt->bt_cyl<<16) + bt->bt_trksec; if (bad < 0) break; bn = (bt->bt_cyl * dp->d_ntracks + (bt->bt_trksec >> 8)) * dp->d_nsectors + (bt->bt_trksec & 0xff); format(f, dp, bn); } exit(0); } struct rp06hdr { short h_cyl; short h_trksec; short h_key1; short h_key2; char h_data[512]; #define RP06_FMT 010000 /* 1 == 16 bit, 0 == 18 bit */ }; /* * Most massbus and unibus drives * have headers of this form */ struct hpuphdr { u_short hpup_cyl; u_short hpup_trksec; char hpup_data[512]; #define HPUP_OKSECT 0xc000 /* this normally means sector is good */ }; struct formats { char *f_name; /* disk name */ int f_bufsize; /* size of sector + header */ int f_bic; /* value to bic in hpup_cyl */ int (*f_routine)(); /* routine for special handling */ } formats[] = { { "rp06", sizeof (struct rp06hdr), RP06_FMT, 0 }, { "eagle", sizeof (struct hpuphdr), HPUP_OKSECT, 0 }, { "capricorn", sizeof (struct hpuphdr), HPUP_OKSECT, 0 }, { 0, 0, 0, 0 } }; format(fd, dp, blk) int fd; struct disktab *dp; daddr_t blk; { register struct formats *fp; char *buf, *malloc(); for (fp = formats; fp->f_name; fp++) if (strcmp(dp->d_name, fp->f_name) == 0) break; if (fp->f_name == 0) { fprintf(stderr, "bad144: don't know how to format %s disks\n", dp->d_name); exit(2); } buf = malloc(fp->f_bufsize); if (buf == NULL) { fprintf(stderr, "bad144: can't allocate sector buffer\n"); exit(3); } /* * Here we do the actual formatting. All we really * do is rewrite the sector header and flag the bad sector * according to the format table description. If a special * purpose format routine is specified, we allow it to * process the sector as well. */ if (lseek(fd, (long)blk * 512, L_SET) < 0) Perror("lseek"); if (ioctl(fd, DKIOCHDR, 0) < 0) Perror("ioctl"); read(fd, buf, fp->f_bufsize); if (fp->f_bic) { struct hpuphdr *xp = (struct hpuphdr *)buf; xp->hpup_cyl &= ~fp->f_bic; } if (fp->f_routine) (*fp->f_routine)(fp, dp, blk, buf); if (lseek(fd, (long)blk * 512, L_SET) < 0) Perror("lseek"); if (ioctl(fd, DKIOCHDR, 0) < 0) Perror("ioctl"); if (write(fd, buf, fp->f_bufsize) != fp->f_bufsize) Perror("write"); } Perror(op) char *op; { fprintf(stderr, "bad144: "); perror(op); exit(4); }