* Copyright (c) 1980 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
"@(#) Copyright (c) 1980 Regents of the University of California.\n\
static char sccsid
[] = "@(#)bad144.c 5.4 (Berkeley) %G%";
* This program prints and/or initializes a bad block record for a pack,
* in the format used by the DEC standard 144.
* It can also add bad sector(s) to the record, moving the sector
* replacements as necessary.
* It is preferable to write the bad information with a standard formatter,
* but this program will do.
* RP06 sectors are marked as bad by inverting the format bit in the
* header; on other drives the valid-sector bit is cleared.
#include <machine/dkio.h>
#define RETRIES 10 /* number of retries on reading old sectors */
int fflag
, add
, copy
, verbose
, nflag
;
struct dkbad dkbad
, oldbad
;
daddr_t size
, getold(), badsn();
register struct bt_bad
*bt
;
int i
, f
, nbad
, new, bad
, errs
;
while (argc
> 0 && **argv
== '-') {
"usage: bad144 [ -f ] type disk [ snum [ bn ... ] ]\n");
"to read or overwrite bad-sector table, e.g.: bad144 rk07 hk0\n");
"or bad144 -a [ -f ] [ -c ] type disk bn ...\n");
fprintf(stderr
, "where options are:\n");
fprintf(stderr
, "\t-a add new bad sectors to the table\n");
fprintf(stderr
, "\t-f reformat listed sectors as bad\n");
fprintf(stderr
, "\t-c copy original sector to replacement\n");
dp
= getdiskbyname(argv
[0]);
fprintf(stderr
, "%s: unknown disk type\n", argv
[0]);
(void)sprintf(name
, "/dev/r%sc", argv
[1]);
(void)strcpy(name
, argv
[1]);
size
= dp
->d_nsectors
* dp
->d_ntracks
* dp
->d_ncylinders
;
f
= open(name
, O_RDONLY
);
printf("bad block information at sector %d in %s:\n",
printf("cartridge serial number: %d(10)\n", dkbad
.bt_csn
);
printf("alignment cartridge\n");
printf("bt_flag=%x(16)?\n", dkbad
.bt_flag
);
for (i
= 0; i
< 126; i
++) {
bad
= (bt
->bt_cyl
<<16) + bt
->bt_trksec
;
printf("sn=%d, cn=%d, tn=%d, sn=%d\n", badsn(bt
),
bt
->bt_cyl
, bt
->bt_trksec
>>8, bt
->bt_trksec
&0xff);
f
= open(name
, (fflag
|| add
)? O_RDWR
: O_WRONLY
);
* Read in the old badsector table.
* Verify that it makes sense, and the bad sectors
* are in order. Copy the old table to the new one.
(void) getold(f
, &oldbad
);
printf("Had %d bad sectors\n", i
);
printf("bad144: not enough room for %d more sectors\n",
printf("limited to 126 by information format\n");
dkbad
.bt_csn
= atoi(*argv
++);
printf("bad144: too many bad sectors specified\n");
printf("limited to 126 by information format\n");
daddr_t sn
= atoi(*argv
++);
if (sn
< 0 || sn
>= size
) {
printf("%d: out of range [0,%d) for %s\n",
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
);
dkbad
.bt_bad
[i
].bt_trksec
= -1;
dkbad
.bt_bad
[i
].bt_cyl
= -1;
* Sort the new bad sectors into the list.
* Then shuffle the replacement sectors so that
* the previous bad sectors get the same replacement data.
qsort((char *)dkbad
.bt_bad
, nbad
, sizeof (struct bt_bad
),
shift(f
, nbad
, nbad
-new);
for (i
= 0; i
< 10 && i
< dp
->d_nsectors
; i
+= 2) {
if (lseek(f
, dp
->d_secsize
* (size
- dp
->d_nsectors
+ i
),
printf("write badsect file at %d\n",
size
- dp
->d_nsectors
+ i
);
write(f
, (caddr_t
)&dkbad
, sizeof dkbad
) != sizeof dkbad
) {
(void)sprintf(msg
, "bad144: write bad sector file %d",
for (i
= nbad
- new; i
< nbad
; i
++)
for (i
= 0; i
< 10 && i
< dp
->d_nsectors
; i
+= 2) {
sn
= size
- dp
->d_nsectors
+ i
;
if (lseek(f
, sn
* dp
->d_secsize
, L_SET
) < 0)
if (read(f
, (char *)bad
, sizeof (*bad
)) == sizeof (*bad
)) {
printf("Using bad-sector file %d\n", i
/2);
(void)sprintf(msg
, "bad144: read bad sector file at sn %d",
"bad144: %s: can't read bad block info\n", name
);
register struct bt_bad
*bt
;
int errors
= 0, warned
= 0;
if (oldbad
.bt_flag
!= 0) {
fprintf(stderr
, "bad144: %s: bad flag in bad-sector table\n",
if (oldbad
.bt_mbz
!= 0) {
fprintf(stderr
, "bad144: %s: bad magic number\n", name
);
for (i
= 0; i
< 126; i
++, bt
++) {
if (bt
->bt_cyl
== -1 && bt
->bt_trksec
== -1)
if ((bt
->bt_cyl
>= dp
->d_ncylinders
) ||
((bt
->bt_trksec
>> 8) >= dp
->d_ntracks
) ||
((bt
->bt_trksec
& 0xff) >= dp
->d_nsectors
)) {
"bad144: cyl/trk/sect out of range in existing entry: ");
fprintf(stderr
, "sn=%d, cn=%d, tn=%d, sn=%d\n",
badsn(bt
), bt
->bt_cyl
, bt
->bt_trksec
>>8,
sn
= (bt
->bt_cyl
* dp
->d_ntracks
+
dp
->d_nsectors
+ (bt
->bt_trksec
& 0xff);
if (sn
< lsn
&& !warned
) {
fprintf(stderr
, "bad144: bad sector file out of order\n");
* Move the bad sector replacements
* to make room for the new bad sectors.
* new is the new number of bad sectors, old is the previous count.
* First replacement is last sector of second-to-last track.
repl
= size
- dp
->d_nsectors
- 1;
while (new >= 0 && new != old
) {
compare(&dkbad
.bt_bad
[new], &oldbad
.bt_bad
[old
]) > 0) {
* Insert new replacement here-- copy original
* sector if requested and possible,
* otherwise write a zero block.
!blkcopy(f
, badsn(&dkbad
.bt_bad
[new]), repl
- new))
if (blkcopy(f
, repl
- old
, repl
- new) == 0)
"Can't copy replacement sector %d to %d\n",
* Copy disk sector s1 to s2.
if (buf
== (char *)NULL
) {
buf
= malloc((unsigned)dp
->d_secsize
);
if (buf
== (char *)NULL
) {
fprintf(stderr
, "Out of memory\n");
if (lseek(f
, dp
->d_secsize
* s1
, L_SET
) < 0)
for (tries
= 0; tries
< RETRIES
; tries
++)
if ((n
= read(f
, buf
, dp
->d_secsize
)) == dp
->d_secsize
)
if (n
!= dp
->d_secsize
) {
fprintf(stderr
, "bad144: can't read sector, %d: ", s1
);
if (lseek(f
, dp
->d_secsize
* s2
, L_SET
) < 0)
printf("copying %d to %d\n", s1
, s2
);
if (nflag
== 0 && write(f
, buf
, dp
->d_secsize
) != dp
->d_secsize
) {
"bad144: can't write replacement sector, %d: ", s2
);
if (zbuf
== (char *)NULL
) {
zbuf
= malloc((unsigned)dp
->d_secsize
);
if (zbuf
== (char *)NULL
) {
fprintf(stderr
, "Out of memory\n");
if (lseek(f
, dp
->d_secsize
* sn
, L_SET
) < 0)
printf("zeroing %d\n", sn
);
if (nflag
== 0 && write(f
, zbuf
, dp
->d_secsize
) != dp
->d_secsize
) {
"bad144: can't write replacement sector, %d: ", sn
);
register struct bt_bad
*b1
, *b2
;
if (b1
->bt_cyl
> b2
->bt_cyl
)
if (b1
->bt_cyl
< b2
->bt_cyl
)
return (b1
->bt_trksec
- b2
->bt_trksec
);
register struct bt_bad
*bt
;
return ((bt
->bt_cyl
*dp
->d_ntracks
+ (bt
->bt_trksec
>>8)) * dp
->d_nsectors
#define RP06_FMT 010000 /* 1 == 16 bit, 0 == 18 bit */
* Most massbus and unibus drives
* have headers of this form
#define HPUP_OKSECT 0xc000 /* this normally means sector is good */
#define HPUP_16BIT 0x1000 /* 1 == 16 bit format */
int rp06format(), hpupformat();
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 */
{ "rp06", sizeof (struct rp06hdr
), RP06_FMT
, rp06format
},
{ "eagle", sizeof (struct hpuphdr
), HPUP_OKSECT
, hpupformat
},
{ "capricorn", sizeof (struct hpuphdr
), HPUP_OKSECT
, hpupformat
},
{ "rm03", sizeof (struct hpuphdr
), HPUP_OKSECT
, hpupformat
},
{ "rm05", sizeof (struct hpuphdr
), HPUP_OKSECT
, hpupformat
},
{ "9300", sizeof (struct hpuphdr
), HPUP_OKSECT
, hpupformat
},
{ "9766", sizeof (struct hpuphdr
), HPUP_OKSECT
, hpupformat
},
hpupformat(fp
, dp
, blk
, buf
, count
)
struct hpuphdr
*hdr
= (struct hpuphdr
*)buf
;
if (count
< sizeof(struct hpuphdr
)) {
hdr
->hpup_cyl
= (HPUP_OKSECT
| HPUP_16BIT
) |
(blk
/ (dp
->d_nsectors
* dp
->d_ntracks
));
sect
= blk
% (dp
->d_nsectors
* dp
->d_ntracks
);
hdr
->hpup_track
= (u_char
)(sect
/ dp
->d_nsectors
);
hdr
->hpup_sect
= (u_char
)(sect
% dp
->d_nsectors
);
rp06format(fp
, dp
, blk
, buf
, count
)
if (count
< sizeof(struct rp06hdr
)) {
fprintf(stderr
, "Can't read header on blk %d, can't reformat\n",
register struct formats
*fp
;
for (fp
= formats
; fp
->f_name
; fp
++)
if (strcmp(dp
->d_name
, fp
->f_name
) == 0)
fprintf(stderr
, "bad144: don't know how to format %s disks\n",
if (buf
&& bufsize
< fp
->f_bufsize
) {
buf
= malloc((unsigned)fp
->f_bufsize
);
fprintf(stderr
, "bad144: can't allocate sector buffer\n");
* 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
* dp
->d_secsize
, L_SET
) < 0)
printf("format blk %d\n", blk
);
if (ioctl(fd
, DKIOCHDR
, (char *)0) < 0)
if ((n
= read(fd
, buf
, fp
->f_bufsize
)) < 0)
bzero(buf
, fp
->f_bufsize
);
struct hpuphdr
*xp
= (struct hpuphdr
*)buf
;
xp
->hpup_cyl
&= ~fp
->f_bic
;
if ((*fp
->f_routine
)(fp
, dp
, blk
, buf
, n
) != 0)
if (lseek(fd
, (long)blk
* dp
->d_secsize
, L_SET
) < 0)
if (ioctl(fd
, DKIOCHDR
, (char *)0) < 0)
if (write(fd
, buf
, fp
->f_bufsize
) != fp
->f_bufsize
) {
(void)sprintf(msg
, "bad144: write format %d", blk
);
fprintf(stderr
, "bad144: "); perror(op
);