#include <sys/param.h>
#include <sys/disklabel_rdb.h>
#include <lib/libkern/libkern.h>
#include <lib/libsa/stand.h>
#include "rdb.h"
static u_long
rdbchksum(void *bdata)
{
u_long *blp, cnt, val;
blp = bdata;
cnt = blp[1];
val = 0;
while (cnt--)
val += *blp++;
return val;
}
static struct adostype
getadostype(u_long dostype)
{
struct adostype adt;
u_long t3, b1;
t3 = dostype & 0xffffff00;
b1 = dostype & 0x000000ff;
adt.fstype = b1;
switch (t3) {
case DOST_NBR:
adt.archtype = ADT_NETBSDROOT;
return adt;
case DOST_NBS:
adt.archtype = ADT_NETBSDSWAP;
return adt;
case DOST_NBU:
adt.archtype = ADT_NETBSDUSER;
return adt;
case DOST_AMIX:
adt.archtype = ADT_AMIX;
if (b1 == 2)
adt.fstype = FS_BSDFFS;
else
adt.fstype = FS_UNUSED;
return adt;
case DOST_XXXBSD:
if (b1 == 'S') {
dostype = DOST_NBS;
dostype |= FS_SWAP;
} else {
if (b1 == 'R')
dostype = DOST_NBR;
else
dostype = DOST_NBU;
dostype |= FS_BSDFFS;
}
return getadostype(dostype);
case DOST_EXT2:
adt.archtype = ADT_EXT2;
adt.fstype = FS_EX2FS;
return adt;
case DOST_RAID:
adt.archtype = ADT_RAID;
adt.fstype = FS_RAID;
return adt;
case DOST_MSD:
adt.archtype = ADT_MSD;
adt.fstype = FS_MSDOS;
return adt;
default:
adt.archtype = ADT_UNKNOWN;
adt.fstype = FS_UNUSED;
return adt;
}
}
int
search_rdb_label(struct of_dev *devp, char *buf, struct disklabel *lp)
{
struct adostype adt;
struct rdblock *rbp;
struct partblock *pbp;
struct disklabel *dlp;
struct partition *pp;
u_long blk;
size_t read;
int i;
rbp = (struct rdblock *)buf;
for (blk = 0; blk < RDB_MAXBLOCKS; blk++) {
if (strategy(devp, F_READ, blk, DEV_BSIZE, buf, &read)
|| read != DEV_BSIZE)
return ERDLAB;
if (rbp->id == RDBLOCK_ID && rdbchksum(rbp) == 0)
break;
dlp = (struct disklabel *)(buf + LABELOFFSET);
if (dlp->d_magic == DISKMAGIC && dkcksum(dlp) == 0) {
*lp = *dlp;
return 0;
}
}
if (blk == RDB_MAXBLOCKS)
return ERDLAB;
lp->d_npartitions = RAW_PART + 1;
for (i = 0; i < MAXPARTITIONS; i++) {
lp->d_partitions[i].p_size = 0;
lp->d_partitions[i].p_offset = 0;
lp->d_partitions[i].p_fstype = 0;
}
lp->d_secsize = rbp->nbytes;
lp->d_nsectors = rbp->nsectors;
lp->d_ntracks = rbp->nheads;
if (rbp->highcyl == 0)
lp->d_ncylinders = rbp->ncylinders;
else
lp->d_ncylinders = rbp->highcyl + 1;
lp->d_secpercyl = (rbp->secpercyl <= lp->d_nsectors * lp->d_ntracks) ?
rbp->secpercyl : lp->d_nsectors * lp->d_ntracks;
if (lp->d_secpercyl == 0)
lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders;
lp->d_acylinders = rbp->ncylinders - (rbp->highcyl - rbp->lowcyl + 1);
lp->d_rpm = 3600;
lp->d_interleave = rbp->interleave;
lp->d_headswitch = lp->d_flags = lp->d_trackskew = lp->d_cylskew = 0;
lp->d_trkseek = 0;
lp->d_partitions[RAW_PART].p_size = rbp->ncylinders * lp->d_secpercyl;
pbp = (struct partblock *)buf;
for (blk = rbp->partbhead; blk != RDBNULL; blk = pbp->next) {
if (strategy(devp, F_READ, blk * (lp->d_secsize / DEV_BSIZE),
lp->d_secsize, buf, &read)
|| read != lp->d_secsize)
return ERDLAB;
if (pbp->id != PARTBLOCK_ID || rdbchksum(pbp))
return ERDLAB;
if (pbp->e.tabsize < 11)
return ERDLAB;
if (pbp->e.tabsize < 16)
pbp->e.dostype = 0;
adt = getadostype(pbp->e.dostype);
switch (adt.archtype) {
case ADT_NETBSDROOT:
pp = &lp->d_partitions[0];
if (pp->p_size)
continue;
break;
case ADT_NETBSDSWAP:
pp = &lp->d_partitions[1];
if (pp->p_size)
continue;
break;
default:
pp = &lp->d_partitions[lp->d_npartitions++];
break;
}
while ((pp - lp->d_partitions) > RAW_PART + 1) {
daddr_t boff;
boff = pbp->e.lowcyl * pbp->e.secpertrk
* pbp->e.numheads
* ((pbp->e.sizeblock << 2) / lp->d_secsize);
if (boff > (pp - 1)->p_offset)
break;
*pp = *(pp - 1);
pp--;
}
pp->p_size = (pbp->e.highcyl - pbp->e.lowcyl + 1)
* pbp->e.secpertrk * pbp->e.numheads
* ((pbp->e.sizeblock << 2) / lp->d_secsize);
pp->p_offset = pbp->e.lowcyl * pbp->e.secpertrk
* pbp->e.numheads
* ((pbp->e.sizeblock << 2) / lp->d_secsize);
pp->p_fstype = adt.fstype;
}
lp->d_magic = lp->d_magic2 = DISKMAGIC;
lp->d_checksum = 0;
lp->d_checksum = dkcksum(lp);
return 0;
}