V10/cmd/rarepl/rarepl.c
/*% cc -O -o rarepl %
*
* replace a bad sector on an RA disk
*/
#include <stdio.h>
#include <sys/param.h>
#include <sys/udaioc.h>
#include "rct.h"
struct ud_unit ud_unit;
int primblk; /* ugh */
int notprim; /* never primary replacement */
#define BADRBN (-1L)
main(argc, argv)
int argc;
char **argv;
{
int fd;
int errs = 0;
if (argc < 3) {
fprintf(stderr, "usage: %s dev lbn ...\n", argv[0]);
exit(1);
}
if ((fd = open(argv[1], 2)) < 0) {
perror(argv[1]);
exit(1);
}
online(fd);
if (ioctl(fd, UIOCHAR, &ud_unit) < 0) {
perror("unit info");
exit(1);
}
argc--;
argv++;
while (--argc > 0)
errs += repl(fd, atol(*++argv));
exit(errs);
}
/*
* read a block from the disk,
* just to make the driver bring it online
*/
online(fd)
int fd;
{
char buf[RBNSEC];
read(fd, buf, RBNSEC); /* ignore error; might be bad sector */
}
/*
* replace a block
*/
repl(fd, bad)
int fd;
daddr_t bad;
{
struct ud_repl r;
char block[RBNSEC];
struct rbd rct[RBNPB];
daddr_t rctb;
int rctoff;
daddr_t rbn;
daddr_t pickrbn();
if (bad >= ud_unit.radsize) {
fprintf(stderr, "%ld: out of range\n", bad);
return (1);
}
clrbuf(block);
lseek(fd, (off_t)(bad * RBNSEC), 0);
read(fd, block, RBNSEC); /* ignore error on purpose */
if ((rbn = pickrbn(fd, bad)) == BADRBN) {
fprintf(stderr, "can't find replacement for %ld\n", bad);
return (1);
}
rctb = (rbn / RBNPB) + RCTTAB;
rctoff = rbn % RBNPB;
if (rdrct(fd, rctb, (char *)rct) == 0)
return (1);
if (rct[rctoff].rb_code) {
fprintf(stderr, "rbn %ld in use or bad\n", rbn);
return (1);
}
rct[rctoff].rb_code = primblk ? RALLOC : RALLOC | RALT;
rct[rctoff].rb_lbn = bad;
if (wrrct(fd, rctb, (char *)rct) == 0)
return (1);
r.lbn = bad;
r.replbn = rbn;
r.prim = primblk;
if (ioctl(fd, UIOREPL, &r) < 0) {
perror("replace ioctl");
return (1);
}
lseek(fd, (off_t)(bad * RBNSEC), 0);
if (write(fd, block, RBNSEC) != RBNSEC) {
perror("write back");
return (1);
}
return (0);
}
/*
* find a replacement block
* remember in primblk whether it's the primary replacement
*/
daddr_t
pickrbn(fd, lbn)
int fd;
daddr_t lbn;
{
struct rbd rct[RBNPB];
daddr_t bno, rbn, prbn;
daddr_t low, high;
register int i;
daddr_t size;
daddr_t rctmax(), primrbn();
size = rctmax();
prbn = primrbn(lbn);
low = high = BADRBN;
for (bno = RCTTAB, rbn = 0L; bno < size; bno++) {
if (rdrct(fd, bno, (char *)rct) == 0) {
rbn += RBNPB;
continue;
}
for (i = 0; i < RBNPB; i++, rbn++) {
if (rct[i].rb_code == RFREE) {
if (rbn < prbn)
low = rbn;
else if (high == BADRBN)
high = rbn;
}
else if (rct[i].rb_lbn == lbn
&& rct[i].rb_code != RNULL
&& rct[i].rb_code != RBAD) {
rct[i].rb_code = RBAD;
wrrct(fd, bno, (char *)rct);
}
}
}
if (low == BADRBN && high == BADRBN)
return (BADRBN);
else if (low == BADRBN)
rbn = high;
else if (high == BADRBN)
rbn = low;
else if (prbn - low < high - prbn)
rbn = low;
else
rbn = high;
if (notprim)
primblk = 0;
else
primblk = (rbn == prbn);
return (rbn);
}
daddr_t
rctmax()
{
register daddr_t nrbns;
nrbns = (ud_unit.radsize / ud_unit.tracksz) * ud_unit.rbns;
nrbns = ((nrbns+RBNPB-1) / RBNPB) + RCTTAB;
if (nrbns >= ud_unit.rctsize) {
notprim = 1;
return ((daddr_t)ud_unit.rctsize);
}
return (nrbns);
}
/*
* figure out the primary RBN
* if notprim == 0, we understand what to do
* otherwise it's not really the primary RBN (and we won't tell the
* controller so), but make a guess about a preferred RBN anyway
*/
daddr_t
primrbn(lbn)
daddr_t lbn;
{
daddr_t q, csize;
if (notprim == 0)
return ((lbn/ud_unit.tracksz) * ud_unit.rbns);
/*
* try for one in the same cylinder,
* or multiple thereof
*/
q = (ud_unit.rctsize - RCTTAB)*RBNPB; /* max possible rbns */
q /= ud_unit.rbns; /* max rbn quantum */
q = ud_unit.radsize/q; /* max LBNs per RBN */
csize = ud_unit.tracksz*ud_unit.groupsz*ud_unit.cylsz;
q = (q + csize - 1)/csize; /* cylinders per RBN */
q *= csize; /* probably real LBNs per RBN */
return ((lbn + csize - 1)/q);
}
rdrct(fd, bno, buf)
int fd;
daddr_t bno;
char *buf;
{
struct ud_rctbuf b;
b.buf = buf;
b.lbn = bno;
if (ioctl(fd, UIORRCT, &b) < 0) {
perror("rrct");
fprintf(stderr, "can't read block %ld of rct\n", bno);
return (0);
}
return (1);
}
wrrct(fd, bno, buf)
int fd;
daddr_t bno;
char *buf;
{
struct ud_rctbuf b;
b.buf = buf;
b.lbn = bno;
if (ioctl(fd, UIOWRCT, &b) < 0) {
perror("wrct");
fprintf(stderr, "can't write block %ld of rct\n", bno);
return (0);
}
return (1);
}
clrbuf(b)
register char *b;
{
register int i;
for (i = 0; i < RBNSEC; i++)
*b++ = 0;
}