#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: disksubr.c,v 1.33 2026/06/11 22:52:09 dbj Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/buf.h>
#define FSTYPENAMES
#include <sys/disklabel.h>
#include <sys/syslog.h>
#include <sys/disk.h>
#include <ufs/ufs/dinode.h>
#include <ufs/ffs/fs.h>
#define b_cylinder b_resid
static uint16_t nextstep_checksum(unsigned char *, unsigned char *);
static const char *parse_nextstep_label(struct next68k_disklabel *,
struct disklabel *, struct cpu_disklabel *);
static int build_nextstep_label(struct next68k_disklabel *, struct disklabel *);
static uint16_t
nextstep_checksum(unsigned char *buf, unsigned char *limit)
{
int sum = 0;
while (buf < limit) {
sum += (buf[0] << 8) + buf[1];
buf += 2;
}
sum += (sum >> 16);
return sum & 0xffff;
}
static const char *
parse_nextstep_label(struct next68k_disklabel *ondisk, struct disklabel *lp,
struct cpu_disklabel *osdep)
{
int i, t, nbp;
uint16_t *checksum;
if (ondisk->cd_version == NEXT68K_LABEL_CD_V3) {
checksum = &ondisk->NEXT68K_LABEL_cd_v3_checksum;
} else {
checksum = &ondisk->NEXT68K_LABEL_cd_checksum;
}
if (nextstep_checksum((uint8_t *)ondisk, (uint8_t *)checksum) !=
*checksum) {
return "disk label corrupted";
}
osdep->od_version = ondisk->cd_version;
lp->d_magic = lp->d_magic2 = DISKMAGIC;
lp->d_type = DKTYPE_SCSI;
lp->d_subtype = 0;
if (sizeof(lp->d_typename) > sizeof(ondisk->cd_name))
lp->d_typename[sizeof (ondisk->cd_name)] = '\0';
memcpy(lp->d_typename, ondisk->cd_name,
uimin(sizeof (lp->d_typename), sizeof(ondisk->cd_name)));
if (sizeof(lp->d_packname) > sizeof(ondisk->cd_label))
lp->d_packname[sizeof (ondisk->cd_label)] = '\0';
memcpy(lp->d_packname, ondisk->cd_label,
uimin(sizeof(lp->d_packname), sizeof(ondisk->cd_label)));
if (lp->d_secsize == 0)
lp->d_secsize = ondisk->cd_secsize;
KASSERT(ondisk->cd_secsize >= lp->d_secsize);
lp->d_nsectors = ondisk->cd_nsectors;
lp->d_ntracks = ondisk->cd_ntracks;
lp->d_ncylinders = ondisk->cd_ncylinders;
lp->d_rpm = ondisk->cd_rpm;
lp->d_flags = ondisk->cd_flags;
lp->d_bbsize = NEXT68K_LABEL_SIZE;
lp->d_sbsize = SBLOCKSIZE;
lp->d_npartitions = nbp = 0;
for (i = 0; i < NEXT68K_LABEL_MAXPARTITIONS - 1; i++) {
if (ondisk->cd_partitions[i].cp_size > 0) {
lp->d_partitions[nbp].p_size =
ondisk->cd_partitions[i].cp_size *
(ondisk->cd_secsize / lp->d_secsize);
lp->d_partitions[nbp].p_offset =
(ondisk->cd_front +
ondisk->cd_partitions[i].cp_offset) *
(ondisk->cd_secsize / lp->d_secsize);
lp->d_partitions[nbp].p_fsize =
ondisk->cd_partitions[i].cp_fsize;
#ifndef FSTYPENAMES
lp->d_partitions[nbp].p_fstype = FS_BSDFFS;
#else
for (t = 0; t < FSMAXTYPES; t++) {
if (strncmp(ondisk->cd_partitions[i].cp_type,
fstypenames[t], NEXT68K_LABEL_MAXFSTLEN)
== 0)
break;
}
if (t == FSMAXTYPES)
t = FS_OTHER;
lp->d_partitions[nbp].p_fstype = t;
#endif
if (ondisk->cd_partitions[i].cp_fsize)
lp->d_partitions[nbp].p_frag =
ondisk->cd_partitions[i].cp_bsize /
ondisk->cd_partitions[i].cp_fsize;
else
lp->d_partitions[nbp].p_frag = 0;
lp->d_partitions[nbp].p_cpg =
ondisk->cd_partitions[i].cp_cpg;
lp->d_npartitions = nbp + 1;
}
nbp++;
if (nbp == RAW_PART)
nbp++;
if (nbp == MAXPARTITIONS)
break;
}
if (lp->d_npartitions <= RAW_PART)
lp->d_npartitions = RAW_PART + 1;
lp->d_checksum = 0;
lp->d_checksum = dkcksum(lp);
return NULL;
}
static int
build_nextstep_label(struct next68k_disklabel *ondisk, struct disklabel *lp)
{
int i, t, nbp;
int front_porch = NEXT68K_LABEL_DEFAULTFRONTPORCH;
uint16_t *checksum;
memset(ondisk, 0, sizeof(*ondisk));
ondisk->cd_version = NEXT68K_LABEL_CD_V3;
strncpy(ondisk->cd_type, "fixed_rw_scsi", sizeof(ondisk->cd_type));
ondisk->cd_secsize = lp->d_secsize;
KASSERT(ondisk->cd_secsize >= lp->d_secsize);
if (memcmp(ondisk->cd_name, lp->d_typename,
uimin(sizeof(lp->d_typename), sizeof(ondisk->cd_name))) &&
sizeof (ondisk->cd_name) > sizeof (lp->d_typename))
ondisk->cd_name[sizeof(lp->d_typename)] = '\0';
memcpy(ondisk->cd_name, lp->d_typename,
uimin(sizeof(lp->d_typename), sizeof(ondisk->cd_name)));
if (memcmp (lp->d_packname, ondisk->cd_label,
uimin(sizeof(lp->d_packname), sizeof(ondisk->cd_label))) &&
sizeof(ondisk->cd_label) > sizeof(lp->d_packname))
ondisk->cd_label[sizeof(lp->d_packname)] = '\0';
memcpy(ondisk->cd_label, lp->d_packname,
uimin(sizeof(lp->d_packname), sizeof(ondisk->cd_label)));
ondisk->cd_nsectors = lp->d_nsectors;
ondisk->cd_ntracks = lp->d_ntracks;
ondisk->cd_ncylinders = lp->d_ncylinders;
ondisk->cd_rpm = lp->d_rpm;
ondisk->cd_flags = lp->d_flags;
for (nbp = 0; nbp < lp->d_npartitions; nbp++) {
if (nbp != RAW_PART && lp->d_partitions[nbp].p_offset > 0 &&
lp->d_partitions[nbp].p_offset < front_porch)
front_porch = lp->d_partitions[nbp].p_offset;
for (t = 0; t < NEXT68K_LABEL_MAXPARTITIONS; t++) {
if (t != (nbp > RAW_PART ? nbp - 1 : nbp) &&
(lp->d_partitions[nbp].p_size ==
ondisk->cd_partitions[t].cp_size *
(ondisk->cd_secsize / lp->d_secsize)) &&
(lp->d_partitions[nbp].p_offset ==
(ondisk->cd_front +
ondisk->cd_partitions[t].cp_offset) *
(ondisk->cd_secsize / lp->d_secsize)) &&
((lp->d_partitions[nbp].p_fstype == FS_OTHER) ||
(!strncmp (ondisk->cd_partitions[t].cp_type,
fstypenames[lp->d_partitions[nbp].p_fstype],
NEXT68K_LABEL_MAXFSTLEN)))) {
struct next68k_partition tmp;
memcpy(&tmp, &ondisk->cd_partitions[t],
sizeof(tmp));
memcpy(&ondisk->cd_partitions[t],
&ondisk->cd_partitions[nbp > RAW_PART ?
nbp - 1 : nbp],
sizeof (tmp));
memcpy(&ondisk->cd_partitions[nbp > RAW_PART ?
nbp - 1 : nbp],
&tmp, sizeof (tmp));
}
}
}
front_porch /= (ondisk->cd_secsize / lp->d_secsize);
nbp = 0;
for (i = 0; i < NEXT68K_LABEL_MAXPARTITIONS; i++) {
struct next68k_partition *p = &ondisk->cd_partitions[i];
if (nbp < lp->d_npartitions && lp->d_partitions[nbp].p_size) {
p->cp_size = lp->d_partitions[nbp].p_size /
(ondisk->cd_secsize / lp->d_secsize);
p->cp_offset = (lp->d_partitions[nbp].p_offset /
(ondisk->cd_secsize / lp->d_secsize)) -
front_porch;
p->cp_bsize = lp->d_partitions[nbp].p_frag
* lp->d_partitions[nbp].p_fsize;
p->cp_fsize = lp->d_partitions[nbp].p_fsize;
if (lp->d_partitions[nbp].p_fstype != FS_OTHER) {
memset(p->cp_type, 0, NEXT68K_LABEL_MAXFSTLEN);
strncpy(p->cp_type,
fstypenames[lp->d_partitions[nbp].p_fstype],
NEXT68K_LABEL_MAXFSTLEN);
}
if (p->cp_density < 0)
p->cp_density = 4096;
if (p->cp_minfree < 0)
p->cp_minfree = 5;
p->cp_cpg = lp->d_partitions[nbp].p_cpg;
} else {
memset(p, 0, sizeof(*p));
p->cp_size = -1;
p->cp_offset = -1;
p->cp_bsize = -1;
p->cp_fsize = -1;
p->cp_density = -1;
p->cp_minfree = -1;
}
nbp++;
if (nbp == RAW_PART)
nbp++;
}
ondisk->cd_front = front_porch;
ondisk->cd_boot_blkno[0] = NEXT68K_LABEL_DEFAULTBOOT0_1 /
(ondisk->cd_secsize / lp->d_secsize);
ondisk->cd_boot_blkno[1] = NEXT68K_LABEL_DEFAULTBOOT0_2 /
(ondisk->cd_secsize / lp->d_secsize);
if (ondisk->cd_version == NEXT68K_LABEL_CD_V3) {
checksum = &ondisk->NEXT68K_LABEL_cd_v3_checksum;
} else {
checksum = &ondisk->NEXT68K_LABEL_cd_checksum;
}
*checksum = nextstep_checksum((uint8_t *)ondisk, (uint8_t *)checksum);
return 0;
}
const char *
readdisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp,
struct cpu_disklabel *osdep)
{
struct buf *bp;
struct disklabel *dlp;
const char *msg = NULL;
int i;
if (lp->d_secsize == 0)
lp->d_secsize = DEV_BSIZE;
if (lp->d_secperunit == 0)
lp->d_secperunit = 0x1fffffff;
lp->d_npartitions = RAW_PART + 1;
for (i = 0; i < RAW_PART; i++) {
lp->d_partitions[i].p_size = 0;
lp->d_partitions[i].p_offset = 0;
}
if (lp->d_partitions[i].p_size == 0)
lp->d_partitions[i].p_size = 0x1fffffff;
lp->d_partitions[i].p_offset = 0;
bp = geteblk(NEXT68K_LABEL_SIZE);
bp->b_dev = dev;
bp->b_blkno = NEXT68K_LABEL_SECTOR;
bp->b_bcount = NEXT68K_LABEL_SIZE;
bp->b_flags |= B_READ;
bp->b_cylinder = NEXT68K_LABEL_SECTOR / lp->d_secpercyl;
(*strat)(bp);
if (osdep)
osdep->od_version = 0;
if (biowait(bp)) {
brelse(bp, 0);
return("I/O error");
}
dlp = (struct disklabel *)
((char *)bp->b_data + LABELSECTOR * lp->d_secsize + LABELOFFSET);
if (dlp->d_magic == DISKMAGIC || dlp->d_magic2 == DISKMAGIC) {
if (osdep)
osdep->od_version = DISKMAGIC;
if (dlp->d_npartitions > MAXPARTITIONS ||
dkcksum(dlp) != 0)
msg = "disk label corrupted";
else {
*lp = *dlp;
msg = NULL;
}
brelse(bp, 0);
return msg;
}
if (IS_DISKLABEL((struct next68k_disklabel *)bp->b_data)) {
msg = parse_nextstep_label(
(struct next68k_disklabel *)bp->b_data, lp, osdep);
brelse(bp, 0);
return msg;
}
msg = "no disk label";
for (dlp = (struct disklabel *)bp->b_data;
dlp <= (struct disklabel *)((char *)bp->b_data +
DEV_BSIZE - sizeof(*dlp));
dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
if (dlp->d_magic == DISKMAGIC || dlp->d_magic2 == DISKMAGIC) {
if (dlp->d_npartitions > MAXPARTITIONS ||
dkcksum(dlp) != 0)
msg = "disk label corrupted";
else {
*lp = *dlp;
msg = NULL;
if (osdep)
osdep->od_version = DISKMAGIC;
break;
}
}
}
brelse(bp, 0);
return msg;
}
int
writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp,
struct cpu_disklabel *osdep)
{
struct buf *bp;
#if 0
struct disklabel *dlp;
#endif
int labelpart;
int error = 0;
labelpart = DISKPART(dev);
if (lp->d_partitions[labelpart].p_offset != 0) {
if (lp->d_partitions[0].p_offset != 0)
return EXDEV;
labelpart = 0;
}
bp = geteblk(NEXT68K_LABEL_SIZE);
bp->b_dev = MAKEDISKDEV(major(dev), DISKUNIT(dev), labelpart);
bp->b_blkno = NEXT68K_LABEL_SECTOR;
bp->b_bcount = NEXT68K_LABEL_SIZE;
bp->b_flags |= B_WRITE;
bp->b_cylinder = NEXT68K_LABEL_SECTOR / lp->d_secpercyl;
error =
build_nextstep_label((struct next68k_disklabel *)bp->b_data, lp);
if (error)
goto done;
#if 0
dlp = (struct disklabel *)
((char *)bp->b_data + LABELSECTOR * lp->d_secsize + LABELOFFSET);
*dlp = *lp;
#endif
(*strat)(bp);
error = biowait(bp);
done:
brelse(bp, 0);
return error;
}