Home | History | Annotate | Line # | Download | only in next68k
      1 /*	$NetBSD: disksubr.c,v 1.33 2026/06/11 22:52:09 dbj Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1982, 1986, 1988, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  * (c) UNIX System Laboratories, Inc.
      7  * All or some portions of this file are derived from material licensed
      8  * to the University of California by American Telephone and Telegraph
      9  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
     10  * the permission of UNIX System Laboratories, Inc.
     11  *
     12  * Redistribution and use in source and binary forms, with or without
     13  * modification, are permitted provided that the following conditions
     14  * are met:
     15  * 1. Redistributions of source code must retain the above copyright
     16  *    notice, this list of conditions and the following disclaimer.
     17  * 2. Redistributions in binary form must reproduce the above copyright
     18  *    notice, this list of conditions and the following disclaimer in the
     19  *    documentation and/or other materials provided with the distribution.
     20  * 3. Neither the name of the University nor the names of its contributors
     21  *    may be used to endorse or promote products derived from this software
     22  *    without specific prior written permission.
     23  *
     24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     34  * SUCH DAMAGE.
     35  *
     36  *	@(#)ufs_disksubr.c	8.5 (Berkeley) 1/21/94
     37  */
     38 
     39 #include <sys/cdefs.h>
     40 __KERNEL_RCSID(0, "$NetBSD: disksubr.c,v 1.33 2026/06/11 22:52:09 dbj Exp $");
     41 
     42 #include <sys/param.h>
     43 #include <sys/systm.h>
     44 #include <sys/buf.h>
     45 #define FSTYPENAMES
     46 #include <sys/disklabel.h>
     47 #include <sys/syslog.h>
     48 
     49 #include <sys/disk.h>
     50 
     51 #include <ufs/ufs/dinode.h>             /* XXX for fs.h */
     52 #include <ufs/ffs/fs.h>                 /* XXX for SBLOCKSIZE */
     53 
     54 #define	b_cylinder	b_resid
     55 
     56 static uint16_t nextstep_checksum(unsigned char *, unsigned char *);
     57 static const char *parse_nextstep_label(struct next68k_disklabel *,
     58     struct disklabel *, struct cpu_disklabel *);
     59 static int build_nextstep_label(struct next68k_disklabel *, struct disklabel *);
     60 
     61 static uint16_t
     62 nextstep_checksum(unsigned char *buf, unsigned char *limit)
     63 {
     64 	int sum = 0;
     65 
     66 	while (buf < limit) {
     67 		sum += (buf[0] << 8) + buf[1];
     68 		buf += 2;
     69 	}
     70 	sum += (sum >> 16);
     71 	return sum & 0xffff;
     72 }
     73 
     74 static const char *
     75 parse_nextstep_label(struct next68k_disklabel *ondisk, struct disklabel *lp,
     76     struct cpu_disklabel *osdep)
     77 {
     78 	int i, t, nbp;
     79 	uint16_t *checksum;
     80 
     81 	if (ondisk->cd_version == NEXT68K_LABEL_CD_V3) {
     82 		checksum = &ondisk->NEXT68K_LABEL_cd_v3_checksum;
     83 	} else {
     84 		checksum = &ondisk->NEXT68K_LABEL_cd_checksum;
     85 	}
     86 	if (nextstep_checksum((uint8_t *)ondisk, (uint8_t *)checksum) !=
     87 	    *checksum) {
     88 		return "disk label corrupted";
     89 	}
     90 
     91 	osdep->od_version = ondisk->cd_version;
     92 	lp->d_magic = lp->d_magic2 = DISKMAGIC;
     93 	lp->d_type = DKTYPE_SCSI;
     94 	lp->d_subtype = 0;
     95 	if (sizeof(lp->d_typename) > sizeof(ondisk->cd_name))
     96 		lp->d_typename[sizeof (ondisk->cd_name)] = '\0';
     97 	memcpy(lp->d_typename, ondisk->cd_name,
     98 	    uimin(sizeof (lp->d_typename), sizeof(ondisk->cd_name)));
     99 	if (sizeof(lp->d_packname) > sizeof(ondisk->cd_label))
    100 		lp->d_packname[sizeof (ondisk->cd_label)] = '\0';
    101 	memcpy(lp->d_packname, ondisk->cd_label,
    102 	    uimin(sizeof(lp->d_packname), sizeof(ondisk->cd_label)));
    103 	if (lp->d_secsize == 0)
    104 		lp->d_secsize = ondisk->cd_secsize;
    105 	KASSERT(ondisk->cd_secsize >= lp->d_secsize);
    106 	lp->d_nsectors = ondisk->cd_nsectors;
    107 	lp->d_ntracks = ondisk->cd_ntracks;
    108 	lp->d_ncylinders = ondisk->cd_ncylinders;
    109 
    110 	lp->d_rpm = ondisk->cd_rpm;
    111 	lp->d_flags = ondisk->cd_flags;
    112 
    113 	lp->d_bbsize = NEXT68K_LABEL_SIZE;
    114 	lp->d_sbsize = SBLOCKSIZE;
    115 
    116 	lp->d_npartitions = nbp = 0;
    117 	for (i = 0; i < NEXT68K_LABEL_MAXPARTITIONS - 1; i++) {
    118 		if (ondisk->cd_partitions[i].cp_size > 0) {
    119 			lp->d_partitions[nbp].p_size =
    120 			    ondisk->cd_partitions[i].cp_size *
    121 			    (ondisk->cd_secsize / lp->d_secsize);
    122 			lp->d_partitions[nbp].p_offset =
    123 			    (ondisk->cd_front +
    124 			     ondisk->cd_partitions[i].cp_offset) *
    125 			     (ondisk->cd_secsize / lp->d_secsize);
    126 			lp->d_partitions[nbp].p_fsize =
    127 			    ondisk->cd_partitions[i].cp_fsize;
    128 #ifndef FSTYPENAMES
    129 			lp->d_partitions[nbp].p_fstype = FS_BSDFFS;
    130 #else
    131 			for (t = 0; t < FSMAXTYPES; t++) {
    132 				if (strncmp(ondisk->cd_partitions[i].cp_type,
    133 				    fstypenames[t], NEXT68K_LABEL_MAXFSTLEN)
    134 				    == 0)
    135 					break;
    136 			}
    137 			if (t == FSMAXTYPES)
    138 				t = FS_OTHER;
    139 			lp->d_partitions[nbp].p_fstype = t;
    140 #endif
    141 			if (ondisk->cd_partitions[i].cp_fsize)
    142 				lp->d_partitions[nbp].p_frag =
    143 				    ondisk->cd_partitions[i].cp_bsize /
    144 				    ondisk->cd_partitions[i].cp_fsize;
    145 			else
    146 				lp->d_partitions[nbp].p_frag = 0;
    147 			lp->d_partitions[nbp].p_cpg =
    148 				ondisk->cd_partitions[i].cp_cpg;
    149 			lp->d_npartitions = nbp + 1;
    150 		}
    151 		nbp++;
    152 		if (nbp == RAW_PART)
    153 			nbp++;
    154 		if (nbp == MAXPARTITIONS)
    155 			break;
    156 	}
    157 
    158 	if (lp->d_npartitions <= RAW_PART)
    159 		lp->d_npartitions = RAW_PART + 1;
    160 
    161 	lp->d_checksum = 0;
    162 	lp->d_checksum = dkcksum(lp);
    163 
    164 	return NULL;
    165 }
    166 
    167 static int
    168 build_nextstep_label(struct next68k_disklabel *ondisk, struct disklabel *lp)
    169 {
    170 	int i, t, nbp;
    171 	int front_porch = NEXT68K_LABEL_DEFAULTFRONTPORCH;
    172 	uint16_t *checksum;
    173 
    174 	memset(ondisk, 0, sizeof(*ondisk));
    175 
    176 	ondisk->cd_version = NEXT68K_LABEL_CD_V3;
    177 	/* ondisk->cd_label_blkno = 0; */
    178 	/* ondisk->cd_size = 0; */
    179 	/* ondisk->cd_tag = 0; */
    180 	strncpy(ondisk->cd_type, "fixed_rw_scsi", sizeof(ondisk->cd_type));
    181 	ondisk->cd_secsize = lp->d_secsize;
    182 	/* ondisk->cd_back = 0; */
    183 	/* ondisk->cd_ngroups = 0; */
    184 	/* ondisk->cd_ag_size = 0; */
    185 	/* ondisk->cd_ag_alts = 0; */
    186 	/* ondisk->cd_ag_off = 0; */
    187 	/* ondisk->kernel */
    188 	/* ondisk->hostname */
    189 	/* ondisk->rootpartition */
    190 	/* ondisk->rwpartition */
    191 	KASSERT(ondisk->cd_secsize >= lp->d_secsize);
    192 
    193 	if (memcmp(ondisk->cd_name, lp->d_typename,
    194 	    uimin(sizeof(lp->d_typename), sizeof(ondisk->cd_name))) &&
    195 	    sizeof (ondisk->cd_name) > sizeof (lp->d_typename))
    196 		ondisk->cd_name[sizeof(lp->d_typename)] = '\0';
    197 	memcpy(ondisk->cd_name, lp->d_typename,
    198 	    uimin(sizeof(lp->d_typename), sizeof(ondisk->cd_name)));
    199 	if (memcmp (lp->d_packname, ondisk->cd_label,
    200 	    uimin(sizeof(lp->d_packname), sizeof(ondisk->cd_label))) &&
    201 	    sizeof(ondisk->cd_label) > sizeof(lp->d_packname))
    202 		ondisk->cd_label[sizeof(lp->d_packname)] = '\0';
    203 	memcpy(ondisk->cd_label, lp->d_packname,
    204 	    uimin(sizeof(lp->d_packname), sizeof(ondisk->cd_label)));
    205 
    206 	ondisk->cd_nsectors = lp->d_nsectors;
    207 	ondisk->cd_ntracks = lp->d_ntracks;
    208 	ondisk->cd_ncylinders = lp->d_ncylinders;
    209 
    210 	ondisk->cd_rpm = lp->d_rpm;
    211 	ondisk->cd_flags = lp->d_flags;
    212 
    213 	/*
    214 	 * figure out front porch
    215 	 * try to map partitions which were moved
    216 	 */
    217 	for (nbp = 0; nbp < lp->d_npartitions; nbp++) {
    218 		if (nbp != RAW_PART && lp->d_partitions[nbp].p_offset > 0 &&
    219 		    lp->d_partitions[nbp].p_offset < front_porch)
    220 			front_porch = lp->d_partitions[nbp].p_offset;
    221 		for (t = 0; t < NEXT68K_LABEL_MAXPARTITIONS; t++) {
    222 			if (t != (nbp > RAW_PART ? nbp - 1 : nbp) &&
    223 			    (lp->d_partitions[nbp].p_size ==
    224 			     ondisk->cd_partitions[t].cp_size *
    225 			     (ondisk->cd_secsize / lp->d_secsize)) &&
    226 			    (lp->d_partitions[nbp].p_offset ==
    227 			     (ondisk->cd_front +
    228 			      ondisk->cd_partitions[t].cp_offset) *
    229 			     (ondisk->cd_secsize / lp->d_secsize)) &&
    230 			    ((lp->d_partitions[nbp].p_fstype == FS_OTHER) ||
    231 			     (!strncmp (ondisk->cd_partitions[t].cp_type,
    232 				 fstypenames[lp->d_partitions[nbp].p_fstype],
    233 				 NEXT68K_LABEL_MAXFSTLEN)))) {
    234 				struct next68k_partition tmp;
    235 				memcpy(&tmp, &ondisk->cd_partitions[t],
    236 				    sizeof(tmp));
    237 				memcpy(&ondisk->cd_partitions[t],
    238 				    &ondisk->cd_partitions[nbp > RAW_PART ?
    239 				    nbp - 1 : nbp],
    240 				    sizeof (tmp));
    241 				memcpy(&ondisk->cd_partitions[nbp > RAW_PART ?
    242 				    nbp - 1 : nbp],
    243 				    &tmp, sizeof (tmp));
    244 			}
    245 		}
    246 	}
    247 	front_porch /= (ondisk->cd_secsize / lp->d_secsize);
    248 
    249 	/*
    250 	 * update partitions
    251 	 */
    252 	nbp = 0;
    253 	for (i = 0; i < NEXT68K_LABEL_MAXPARTITIONS; i++) {
    254 		struct next68k_partition *p = &ondisk->cd_partitions[i];
    255 		if (nbp < lp->d_npartitions && lp->d_partitions[nbp].p_size) {
    256 			p->cp_size = lp->d_partitions[nbp].p_size /
    257 			    (ondisk->cd_secsize / lp->d_secsize);
    258 			p->cp_offset = (lp->d_partitions[nbp].p_offset /
    259 			    (ondisk->cd_secsize / lp->d_secsize)) -
    260 			    front_porch;
    261 			p->cp_bsize = lp->d_partitions[nbp].p_frag
    262 			    * lp->d_partitions[nbp].p_fsize;
    263 			p->cp_fsize = lp->d_partitions[nbp].p_fsize;
    264 			if (lp->d_partitions[nbp].p_fstype != FS_OTHER) {
    265 				memset(p->cp_type, 0, NEXT68K_LABEL_MAXFSTLEN);
    266 				strncpy(p->cp_type,
    267 				    fstypenames[lp->d_partitions[nbp].p_fstype],
    268 				    NEXT68K_LABEL_MAXFSTLEN);
    269 			}
    270 			if (p->cp_density < 0)
    271 				p->cp_density = 4096; /* set some default */
    272 			if (p->cp_minfree < 0)
    273 				p->cp_minfree = 5; /* set some default */
    274 			p->cp_cpg = lp->d_partitions[nbp].p_cpg;
    275 		} else {
    276 			memset(p, 0, sizeof(*p));
    277 			p->cp_size = -1;
    278 			p->cp_offset = -1;
    279 			p->cp_bsize = -1;
    280 			p->cp_fsize = -1;
    281 			p->cp_density = -1;
    282 			p->cp_minfree = -1;
    283 		}
    284 		nbp++;
    285 		if (nbp == RAW_PART)
    286 			nbp++;
    287 	}
    288 
    289 	ondisk->cd_front = front_porch;
    290 	ondisk->cd_boot_blkno[0] = NEXT68K_LABEL_DEFAULTBOOT0_1 /
    291 	    (ondisk->cd_secsize / lp->d_secsize);
    292 	ondisk->cd_boot_blkno[1] = NEXT68K_LABEL_DEFAULTBOOT0_2 /
    293 	    (ondisk->cd_secsize / lp->d_secsize);
    294 
    295 	if (ondisk->cd_version == NEXT68K_LABEL_CD_V3) {
    296 		checksum = &ondisk->NEXT68K_LABEL_cd_v3_checksum;
    297 	} else {
    298 		checksum = &ondisk->NEXT68K_LABEL_cd_checksum;
    299 	}
    300 	*checksum = nextstep_checksum((uint8_t *)ondisk, (uint8_t *)checksum);
    301 
    302 	return 0;
    303 }
    304 
    305 /*
    306  * Attempt to read a disk label from a device using the indicated strategy
    307  * routine.  The label must be partly set up before this: secpercyl and
    308  * anything required in the strategy routine (e.g., sector size) must be
    309  * filled in before calling us.  Returns null on success and an error
    310  * string on failure.
    311  */
    312 const char *
    313 readdisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp,
    314     struct cpu_disklabel *osdep)
    315 {
    316 	struct buf *bp;
    317 	struct disklabel *dlp;
    318 	const char *msg = NULL;
    319 	int i;
    320 
    321 	/* minimal requirements for archetypal disk label */
    322 	if (lp->d_secsize == 0)
    323 		lp->d_secsize = DEV_BSIZE;
    324 	if (lp->d_secperunit == 0)
    325 		lp->d_secperunit = 0x1fffffff;
    326 	lp->d_npartitions = RAW_PART + 1;
    327 	for (i = 0; i < RAW_PART; i++) {
    328 		lp->d_partitions[i].p_size = 0;
    329 		lp->d_partitions[i].p_offset = 0;
    330 	}
    331 	if (lp->d_partitions[i].p_size == 0)
    332 		lp->d_partitions[i].p_size = 0x1fffffff;
    333 	lp->d_partitions[i].p_offset = 0;
    334 
    335 	bp = geteblk(NEXT68K_LABEL_SIZE);
    336 	bp->b_dev = dev;
    337 	bp->b_blkno = NEXT68K_LABEL_SECTOR;
    338 	bp->b_bcount = NEXT68K_LABEL_SIZE;
    339 	bp->b_flags |= B_READ;
    340 	bp->b_cylinder = NEXT68K_LABEL_SECTOR / lp->d_secpercyl;
    341 	(*strat)(bp);
    342 
    343 	if (osdep)
    344 		osdep->od_version = 0;
    345 
    346 	if (biowait(bp)) {
    347 		brelse(bp, 0);
    348 		return("I/O error");
    349 	}
    350 	dlp = (struct disklabel *)
    351 	    ((char *)bp->b_data + LABELSECTOR * lp->d_secsize + LABELOFFSET);
    352 	if (dlp->d_magic == DISKMAGIC || dlp->d_magic2 == DISKMAGIC) {
    353 		/* got a NetBSD disklabel */
    354 		if (osdep)
    355 			osdep->od_version = DISKMAGIC;
    356 		if (dlp->d_npartitions > MAXPARTITIONS ||
    357 			   dkcksum(dlp) != 0)
    358 			msg = "disk label corrupted";
    359 		else {
    360 			*lp = *dlp;
    361 			msg = NULL;
    362 		}
    363 		brelse(bp, 0);
    364 		return msg;
    365 	}
    366 	if (IS_DISKLABEL((struct next68k_disklabel *)bp->b_data)) {
    367 		/* got a NeXT disklabel */
    368 		msg = parse_nextstep_label(
    369 		    (struct next68k_disklabel *)bp->b_data, lp, osdep);
    370 		brelse(bp, 0);
    371 		return msg;
    372 	}
    373 	/*
    374 	 * no disklabel at the usual places. Try to locate a NetBSD disklabel
    375 	 * in the first sector. This ensure compatibility with others
    376 	 * big-endian systems, and with next68k when LABELSECTOR was 0.
    377 	 */
    378 	msg = "no disk label";
    379 	for (dlp = (struct disklabel *)bp->b_data;
    380 	     dlp <= (struct disklabel *)((char *)bp->b_data +
    381 	     DEV_BSIZE - sizeof(*dlp));
    382 	     dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
    383 		if (dlp->d_magic == DISKMAGIC || dlp->d_magic2 == DISKMAGIC) {
    384 			if (dlp->d_npartitions > MAXPARTITIONS ||
    385 			   dkcksum(dlp) != 0)
    386 				msg = "disk label corrupted";
    387 			else {
    388 				*lp = *dlp;
    389 				msg = NULL;
    390 				if (osdep)
    391 					osdep->od_version = DISKMAGIC;
    392 				break;
    393 			}
    394 		}
    395 	}
    396 	brelse(bp, 0);
    397 	return msg;
    398 }
    399 
    400 /*
    401  * Write disk label back to device after modification.
    402  */
    403 int
    404 writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp,
    405     struct cpu_disklabel *osdep)
    406 {
    407 	struct buf *bp;
    408 #if 0
    409 	struct disklabel *dlp;
    410 #endif
    411 	int labelpart;
    412 	int error = 0;
    413 
    414 	labelpart = DISKPART(dev);
    415 	if (lp->d_partitions[labelpart].p_offset != 0) {
    416 		if (lp->d_partitions[0].p_offset != 0)
    417 			return EXDEV;			/* not quite right */
    418 		labelpart = 0;
    419 	}
    420 	/*
    421 	 * We always write a NeXT v3 disklabel, and a NetBSD disklabel in
    422 	 * the last sector of the NeXT label area.
    423 	 */
    424 
    425 	bp = geteblk(NEXT68K_LABEL_SIZE);
    426 	bp->b_dev = MAKEDISKDEV(major(dev), DISKUNIT(dev), labelpart);
    427 	bp->b_blkno = NEXT68K_LABEL_SECTOR;
    428 	bp->b_bcount = NEXT68K_LABEL_SIZE;
    429 	bp->b_flags |= B_WRITE;
    430 	bp->b_cylinder = NEXT68K_LABEL_SECTOR / lp->d_secpercyl;
    431 	error =
    432 	    build_nextstep_label((struct next68k_disklabel *)bp->b_data, lp);
    433 	if (error)
    434 		goto done;
    435 #if 0
    436 	dlp = (struct disklabel *)
    437 	    ((char *)bp->b_data + LABELSECTOR * lp->d_secsize + LABELOFFSET);
    438 	*dlp = *lp;
    439 #endif
    440 	(*strat)(bp);
    441 	error = biowait(bp);
    442  done:
    443 	brelse(bp, 0);
    444 	return error;
    445 }
    446