f6d2179b7eb054fa70ef22506431090a44e97f3c
* Copyright (c) 1993, 198019861988
* The Regents of the University of California. All rights reserved.
* %sccs.include.redist.c%
static char copyright
[] =
"@(#) Copyright (c) 1993, 198019861988\n\
The Regents of the University of California. All rights reserved.\n";
static char sccsid
[] = "@(#)bad144.c 8.1 (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 <sys/disklabel.h>
#define RETRIES 10 /* number of retries on reading old sectors */
#define RAWPART "c" /* disk partition containing badsector tables */
int fflag
, add
, copy
, verbose
, nflag
;
int badfile
= -1; /* copy of badsector table to use, -1 if any */
struct dkbad curbad
, oldbad
;
daddr_t size
, getold(), badsn();
register struct bt_bad
*bt
;
int i
, f
, nbad
, new, bad
, errs
;
while (argc
> 0 && **argv
== '-') {
if (**argv
>= '0' && **argv
<= '4') {
"usage: bad144 [ -f ] disk [ snum [ bn ... ] ]\n");
"to read or overwrite bad-sector table, e.g.: bad144 hp0\n");
"or bad144 -a [ -f ] [ -c ] 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");
(void)sprintf(name
, "%s/r%s%s", _PATH_DEV
, argv
[0], RAWPART
);
f
= open(name
, argc
== 1? O_RDONLY
: O_RDWR
);
if (read(f
, label
, sizeof(label
)) < 0)
for (dp
= (struct disklabel
*)(label
+ LABELOFFSET
);
dp
< (struct disklabel
*)
(label
+ sizeof(label
) - sizeof(struct disklabel
));
dp
= (struct disklabel
*)((char *)dp
+ 64))
if (dp
->d_magic
== DISKMAGIC
&& dp
->d_magic2
== DISKMAGIC
)
if (dp
->d_magic
!= DISKMAGIC
|| dp
->d_magic2
!= DISKMAGIC
) {
fprintf(stderr
, "Bad pack magic number (pack is unlabeled)\n");
if (dp
->d_secsize
> MAXSECSIZE
|| dp
->d_secsize
<= 0) {
fprintf(stderr
, "Disk sector size too large/small (%d)\n",
size
= dp
->d_nsectors
* dp
->d_ntracks
* dp
->d_ncylinders
;
printf("bad block information at sector %d in %s:\n",
printf("cartridge serial number: %d(10)\n", oldbad
.bt_csn
);
switch (oldbad
.bt_flag
) {
printf("alignment cartridge\n");
printf("bt_flag=%x(16)?\n", oldbad
.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);
(void) checkold(&oldbad
);
* 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, adding %d\n", i
, argc
);
printf("bad144: not enough room for %d more sectors\n",
printf("limited to 126 by information format\n");
curbad
.bt_csn
= atoi(*argv
++);
curbad
.bt_flag
= DKBAD_MAGIC
;
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 disk %s\n",
sn
, size
, dp
->d_typename
);
curbad
.bt_bad
[i
].bt_cyl
= sn
/ (dp
->d_nsectors
*dp
->d_ntracks
);
sn
%= (dp
->d_nsectors
*dp
->d_ntracks
);
curbad
.bt_bad
[i
].bt_trksec
=
((sn
/dp
->d_nsectors
) << 8) + (sn
%dp
->d_nsectors
);
curbad
.bt_bad
[i
].bt_trksec
= -1;
curbad
.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 *)curbad
.bt_bad
, nbad
, sizeof (struct bt_bad
),
"bad144: bad sectors have been duplicated; can't add existing sectors\n");
shift(f
, nbad
, nbad
-new);
for (; 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
);
if (nflag
== 0 && write(f
, (caddr_t
)&curbad
, sizeof(curbad
)) !=
(void)sprintf(msg
, "bad144: write bad sector file %d",
for (i
= nbad
- new; i
< nbad
; i
++)
if (nflag
== 0 && ioctl(f
, DIOCSBAD
, (caddr_t
)&curbad
) < 0)
"Can't sync bad-sector file; reboot for changes to take effect\n");
for (; 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
, dp
->d_secsize
) == dp
->d_secsize
) {
printf("Using bad-sector file %d\n", i
/2);
(void)sprintf(msg
, "bad144: read bad sector file at sn %d", sn
);
fprintf(stderr
, "bad144: %s: can't read bad block info\n", name
);
register struct bt_bad
*bt
;
int errors
= 0, warned
= 0;
if (oldbad
.bt_flag
!= DKBAD_MAGIC
) {
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
== 0xffff && bt
->bt_trksec
== 0xffff)
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 (i
> 0 && sn
< lsn
&& !warned
) {
"bad144: bad sector file is out of order\n");
if (i
> 0 && sn
== lsn
) {
"bad144: bad sector file contains duplicates (sn %d)\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(&curbad
.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(&curbad
.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");
for (tries
= 0; tries
< RETRIES
; tries
++) {
if (lseek(f
, dp
->d_secsize
* s1
, L_SET
) < 0)
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
)
if (b1
->bt_trksec
== b2
->bt_trksec
)
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_typename
, 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.
printf("format blk %d\n", blk
);
bzero((char *)&fop
, sizeof(fop
));
fop
.df_count
= fp
->f_bufsize
;
bzero(buf
, fp
->f_bufsize
);
if (ioctl(fd
, DIOCRFORMAT
, &fop
) < 0)
perror("bad144: read format");
(*fp
->f_routine
)(fp
, dp
, blk
, buf
, fop
.df_count
) != 0)
struct hpuphdr
*xp
= (struct hpuphdr
*)buf
;
xp
->hpup_cyl
&= ~fp
->f_bic
;
bzero((char *)&fop
, sizeof(fop
));
fop
.df_count
= fp
->f_bufsize
;
if (ioctl(fd
, DIOCWFORMAT
, &fop
) < 0)
if (fop
.df_count
!= fp
->f_bufsize
) {
(void)sprintf(msg
, "bad144: write format %d", blk
);
fprintf(stderr
, "bad144: "); perror(op
);