fixes from ghg
[unix-history] / usr / src / sys / vax / stand / format.c
/* format.c 6.2 83/09/18 */
/*
* Standalone program to do media checking
* and record bad block information on any
* disk with the appropriate driver and RM03-style headers.
*/
#include "../h/param.h"
#include "../h/fs.h"
#include "../h/inode.h"
#include "../h/dkbad.h"
#include "../h/vmmac.h"
#include "saio.h"
#include "savax.h"
#define MAXBADDESC 126 /* size of bad block table */
#define CHUNK 48 /* max # of sectors/io operation */
#define SECTSIZ 512 /* standard sector size */
#define HDRSIZ 4 /* number of bytes in sector header */
#define SSERR 0
#define BSERR 1
#define SSDEV ((ioctl(iob[fd-3], SAIOSSDEV, (char *)0) == 0))
struct sector {
u_short header1;
u_short header2;
char buf[SECTSIZ];
};
struct dkbad dkbad; /* bad sector table */
struct dkbad sstab; /* skip sector table */
#define NERRORS 6
static char *
errornames[NERRORS] = {
#define FE_BSE 0
"Bad sector",
#define FE_WCE 1
"Write check",
#define FE_ECC 2
"ECC",
#define FE_HARD 3
"Other hard",
#define FE_TOTAL 4
"Total",
#define FE_SSE 5
"Skip sector",
};
int errors[NERRORS]; /* histogram of errors */
int pattern;
char *malloc();
char *prompt();
extern int end;
main()
{
register int sector, sn;
int lastsector, tracksize;
int unit, fd, resid, i, trk, cyl, debug;
struct st st;
struct sector *bp, *cbp;
char *cp;
printf("Disk format/check utility\n\n");
again:
cp = prompt("Enable debugging (1=bse, 2=ecc, 3=bse+ecc)? ");
debug = atoi(cp);
if (debug < 0)
debug = 0;
for (i = 0; i < NERRORS; i++)
errors[i] = 0;
fd = getdevice();
ioctl(fd, SAIODEVDATA, &st);
printf("Device data: #cylinders=%d, #tracks=%d, #sectors=%d\n",
st.ncyl, st.ntrak, st.nsect);
if (getpattern())
goto again;
printf("Start formatting...make sure the drive is online\n");
ioctl(fd, SAIONOBAD, (char *)0);
ioctl(fd, SAIOECCLIM, (char *)0);
ioctl(fd, SAIODEBUG, (char *)debug);
if (SSDEV) {
ioctl(fd, SAIOSSI, (char *)0); /* set skip sector inhibit */
st.nsect++;
st.nspc += st.ntrak;
}
tracksize = sizeof (struct sector) * st.nsect;
bp = (struct sector *)malloc(tracksize);
bufinit(bp, tracksize);
/*
* Begin check, for each track,
*
* 1) Write header and test pattern.
* 2) Write check header and data.
*/
lastsector = st.nspc * st.ncyl;
for (sector = 0; sector < lastsector; sector += st.nsect) {
cyl = sector / st.nspc;
trk = (sector % st.nspc) / st.nsect;
for (i = 0; i < st.nsect; i++) {
bp[i].header1 =
(u_short) cyl | HDR1_FMT22 | HDR1_OKSCT;
bp[i].header2 = ((u_short)trk << 8) + i;
}
if (sector && (sector % (st.nspc * 10)) == 0)
printf("cylinder %d\n", cyl);
/*
* Try and write the headers and data patterns into
* each sector in the track. Continue until such
* we're done, or until there's less than a sector's
* worth of data to transfer.
*
* The lseek call is necessary because of
* the odd sector size (516 bytes)
*/
for (resid = tracksize, cbp = bp, sn = sector;;) {
int cc;
lseek(fd, sn * SECTSIZ, 0);
ioctl(fd, SAIOHDR, (char *)0);
cc = write(fd, cbp, resid);
if (cc == resid)
break;
/*
* Don't record errors during write,
* all errors will be found during
* writecheck performed below.
*/
sn = iob[fd - 3].i_errblk;
cbp += sn - sector;
resid -= (sn - sector) * sizeof (struct sector);
if (resid < sizeof (struct sector))
break;
}
/*
* Write check headers and test patterns.
* Retry remainder of track on error until
* we're done, or until there's less than a
* sector to verify.
*/
for (resid = tracksize, cbp = bp, sn = sector;;) {
int cc;
lseek(fd, sn * SECTSIZ, 0);
ioctl(fd, SAIOHCHECK, (char *)0);
cc = read(fd, cbp, resid);
if (cc == resid)
break;
sn = iob[fd-3].i_errblk;
printf("sector %d, write check error\n", sn);
recorderror(fd, sn, &st);
/* advance past bad sector */
sn++;
cbp += sn - sector;
resid -= (sn - sector) * sizeof (struct sector);
if (resid < sizeof (struct sector))
break;
}
}
/*
* Checking finished.
*/
if (errors[FE_TOTAL] || errors[FE_SSE]) {
printf("Errors:\n");
for (i = 0; i < NERRORS; i++)
printf("%s: %d\n", errornames[i], errors[i]);
printf("Total of %d hard errors found\n",
errors[FE_TOTAL] + errors[FE_SSE]);
/* change the headers of all the bad sectors */
writebb(fd, errors[FE_SSE], &sstab, &st, SSERR);
writebb(fd, errors[FE_TOTAL], &dkbad, &st, BSERR);
}
while (errors[FE_TOTAL] < MAXBADDESC) {
int i = errors[FE_TOTAL]++;
dkbad.bt_bad[i].bt_cyl = -1;
dkbad.bt_bad[i].bt_trksec = -1;
}
printf("\nWriting bad sector table at sector #%d\n",
st.ncyl * st.nspc - st.nsect);
/* place on disk */
for (i = 0; i < 10; i += 2) {
lseek(fd, SECTSIZ * (st.ncyl * st.nspc - st.nsect + i), 0);
write(fd, &dkbad, sizeof (dkbad));
}
printf("Done\n");
ioctl(fd,SAIONOSSI,(char *)0);
close(fd);
#ifndef JUSTEXIT
goto again;
#endif
}
/*
* Write out the bad blocks.
*/
writebb(fd, nsects, dbad, st, sw)
int nsects, fd;
struct dkbad *dbad;
register struct st *st;
{
struct sector bb_buf; /* buffer for one sector plus 4 byte header */
register int i;
int bn, j;
struct bt_bad *btp;
for (i = 0; i < nsects; i++) {
btp = &dbad->bt_bad[i];
if (sw == BSERR) {
bb_buf.header1 = HDR1_FMT22|btp->bt_cyl;
if (SSDEV)
bb_buf.header1 |= HDR1_SSF;
} else
bb_buf.header1 =
btp->bt_cyl | HDR1_FMT22 | HDR1_SSF | HDR1_OKSCT;
bb_buf.header2 = btp->bt_trksec;
bn = st->nspc * btp->bt_cyl +
st->nsect * (btp->bt_trksec >> 8) +
(btp->bt_trksec & 0xff);
lseek(fd, bn * SECTSIZ, 0);
ioctl(fd, SAIOHDR, (char *)0);
write(fd, &bb_buf, sizeof (bb_buf));
if (!SSDEV)
continue;
/*
* If skip sector, mark all remaining
* sectors on the track.
*/
for (j = (btp->bt_trksec & 0xff) + 1; j < st->nsect; j++) {
bb_buf.header1 = j | HDR1_FMT22 | HDR1_SSF;
ioctl(fd, SAIOHDR, (char *)0);
write(fd, &bb_buf, sizeof (bb_buf));
}
}
}
/*
* Record an error, and if there's room, put
* it in the appropriate bad sector table.
*/
recorderror(fd, bn, st)
int fd, bn;
register struct st *st;
{
int cn, tn, sn, strk;
if (errors[FE_TOTAL] >= MAXBADDESC) {
printf("Too many bad sectors\n");
return;
}
if (errors[FE_SSE] >= MAXBADDESC) {
printf("Too many skip sector errors\n");
return;
}
if (errno < EBSE || errno > EHER)
return;
errno -= EBSE;
errors[errno]++;
cn = bn / st->nspc;
sn = bn % st->nspc;
tn = sn / st->nsect;
sn %= st->nsect;
if (SSDEV) { /* if drive has skip sector capability */
int ss = errors[FE_SSE]++;
if (ss)
strk = sstab.bt_bad[ss - 1].bt_trksec >> 8;
else
strk = -1;
if (tn != strk) { /* only one skip sector/track */
sstab.bt_bad[ss].bt_cyl = cn;
sstab.bt_bad[ss].bt_trksec = (tn<<8) + sn;
return;
}
cn = -cn;
}
/* record the bad sector address and continue */
dkbad.bt_bad[errors[FE_TOTAL]].bt_cyl = cn;
dkbad.bt_bad[errors[FE_TOTAL]++].bt_trksec = (tn << 8) + sn;
}
/*
* Allocate memory on a page-aligned address.
* Round allocated chunk to a page multiple to
* ease next request.
*/
char *
malloc(size)
int size;
{
char *result;
static caddr_t last = 0;
if (last == 0)
last = (caddr_t)(((int)&end + 511) & ~0x1ff);
size = (size + 511) & ~0x1ff;
result = (char *)last;
last += size;
return (result);
}
/*
* Prompt and verify a device name from the user.
*/
getdevice()
{
register char *cp;
register struct devsw *dp;
int fd;
top:
cp = prompt("Device to format? ");
if ((fd = open(cp, 2)) < 0) {
printf("Known devices are: ");
for (dp = devsw; dp->dv_name; dp++)
printf("%s ",dp->dv_name);
printf("\n");
goto top;
}
printf("Formatting drive %d on %c%c%d ",
iob[fd - 3].i_unit % 8, cp[0], cp[1], iob[fd - 3].i_unit / 8);
cp = prompt("verify (yes/no)? ");
while (*cp != 'y' && *cp != 'n')
cp = prompt("Huh, yes or no? ");
if (*cp == 'y')
return (fd);
goto top;
}
static struct pattern {
long pa_value;
char *pa_name;
} pat[] = {
{ 0xf00ff00f, "RH750 worst case" },
{ 0xec6dec6d, "media worst case" },
{ 0xa5a5a5a5, "alternate 1's and 0's" },
{ 0, 0 },
};
getpattern()
{
register struct pattern *p;
int npatterns;
char *cp;
printf("Available test patterns are:\n");
for (p = pat; p->pa_value; p++)
printf("\t%d - (%x) %s\n", (p - pat) + 1,
p->pa_value & 0xffff, p->pa_name);
npatterns = p - pat;
cp = prompt("Pattern (one of the above, other to restart)? ");
pattern = atoi(cp) - 1;
return (pattern < 0 || pattern >= npatterns);
}
struct xsect {
u_short hd1;
u_short hd2;
long buf[128];
};
/*
* Initialize the buffer with the requested pattern.
*/
bufinit(bp, size)
register struct xsect *bp;
int size;
{
register struct pattern *pptr;
register long *pp, *last;
register struct xsect *lastbuf;
size /= sizeof (struct sector);
lastbuf = bp + size;
pptr = &pat[pattern];
while (bp < lastbuf) {
last = &bp->buf[128];
for (pp = bp->buf; pp < last; pp++)
*pp = pptr->pa_value;
bp++;
}
}
char *
prompt(msg)
char *msg;
{
static char buf[132];
printf("%s", msg);
gets(buf);
return (buf);
}