Home | History | Annotate | Line # | Download | only in playstation2
      1 /*	$NetBSD: disksubr.c,v 1.23 2026/07/14 13:34:35 thorpej Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. Neither the name of the University nor the names of its contributors
     16  *    may be used to endorse or promote products derived from this software
     17  *    without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  * SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 __KERNEL_RCSID(0, "$NetBSD: disksubr.c,v 1.23 2026/07/14 13:34:35 thorpej Exp $");
     34 
     35 #include <sys/param.h>
     36 #include <sys/systm.h>
     37 #include <sys/buf.h>
     38 #include <sys/disklabel.h>
     39 #include <sys/disk.h>
     40 
     41 #define NO_MBR_SIGNATURE ((struct mbr_partition *) -1)
     42 
     43 static struct mbr_partition *
     44 mbr_findslice(struct mbr_partition* dp, struct buf *bp);
     45 
     46 /*
     47  * Scan MBR for NetBSD partition.  Return NO_MBR_SIGNATURE if no MBR found
     48  * Otherwise, copy valid MBR partition-table into dp, and if a NetBSD
     49  * partition is found, return a pointer to it; else return  NULL.
     50  */
     51 static
     52 struct mbr_partition *
     53 mbr_findslice(struct mbr_partition *dp, struct buf *bp)
     54 {
     55 	struct mbr_partition *ourdp = NULL;
     56 	u_int16_t *mbrmagicp;
     57 	int i;
     58 
     59 	/* Note: Magic number is little-endian. */
     60 	mbrmagicp = (u_int16_t *)((char*)bp->b_data + MBR_MAGIC_OFFSET);
     61 	if (*mbrmagicp != MBR_MAGIC)
     62 		return (NO_MBR_SIGNATURE);
     63 
     64 	/* XXX how do we check veracity/bounds of this? */
     65 	memcpy(dp, (char*)bp->b_data + MBR_PART_OFFSET, MBR_PART_COUNT * sizeof(*dp));
     66 
     67 	/* look for NetBSD partition */
     68 	for (i = 0; i < MBR_PART_COUNT; i++) {
     69 		if (dp[i].mbrp_type == MBR_PTYPE_NETBSD) {
     70 			ourdp = &dp[i];
     71 			break;
     72 		}
     73 	}
     74 
     75 	return (ourdp);
     76 }
     77 
     78 
     79 /*
     80  * Attempt to read a disk label from a device
     81  * using the indicated strategy routine.
     82  * The label must be partly set up before this:
     83  * secpercyl, secsize and anything required for a block i/o read
     84  * operation in the driver's strategy/start routines
     85  * must be filled in before calling us.
     86  *
     87  * If dos partition table requested, attempt to load it and
     88  * find disklabel inside a DOS partition. Also, if bad block
     89  * table needed, attempt to extract it as well. Return buffer
     90  * for use in signalling errors if requested.
     91  *
     92  * Returns null on success and an error string on failure.
     93  */
     94 const char *
     95 readdisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp,
     96     struct cpu_disklabel *osdep)
     97 {
     98 	struct mbr_partition *dp;
     99 	struct partition *pp;
    100 	struct buf *bp;
    101 	struct disklabel *dlp;
    102 	const char *msg = NULL;
    103 	int dospartoff, cyl, i;
    104 
    105 	/* minimal requirements for archetypal disk label */
    106 	if (lp->d_secsize == 0)
    107 		lp->d_secsize = DEV_BSIZE;
    108 	if (lp->d_secperunit == 0)
    109 		lp->d_secperunit = 0x1fffffff;
    110 #if 0
    111 	if (lp->d_ncylinders == 16383) {
    112 		printf("disklabel: Disk > 8G ... readjusting chs %d/%d/%d to ",
    113 			lp->d_ncylinders, lp->d_ntracks, lp->d_nsectors);
    114 		lp->d_ncylinders = lp->d_secperunit /  lp->d_ntracks / lp->d_nsectors;
    115 		printf("%d/%d/%d\n",
    116 			lp->d_ncylinders, lp->d_ntracks, lp->d_nsectors);
    117 	}
    118 #endif
    119 	lp->d_npartitions = RAW_PART + 1;
    120 	for (i = 0; i < RAW_PART; i++) {
    121 		lp->d_partitions[i].p_size = 0;
    122 		lp->d_partitions[i].p_offset = 0;
    123 	}
    124 	if (lp->d_partitions[i].p_size == 0)
    125 		lp->d_partitions[i].p_size = 0x1fffffff;
    126 	lp->d_partitions[i].p_offset = 0;
    127 
    128 	/* get a buffer and initialize it */
    129 	bp = geteblk((int)lp->d_secsize);
    130 	bp->b_dev = dev;
    131 
    132 	/* do dos partitions in the process of getting disklabel? */
    133 	dospartoff = 0;
    134 	cyl = LABELSECTOR / lp->d_secpercyl;
    135 	if (!osdep)
    136 		goto nombrpart;
    137 	dp = osdep->dosparts;
    138 
    139 	/* read master boot record */
    140 	bp->b_blkno = MBR_BBSECTOR;
    141 	bp->b_bcount = lp->d_secsize;
    142 	bp->b_flags |= B_READ;
    143 	bp->b_cylinder = MBR_BBSECTOR / lp->d_secpercyl;
    144 	(*strat)(bp);
    145 
    146 	/* if successful, wander through dos partition table */
    147 	if (biowait(bp)) {
    148 		msg = "dos partition I/O error";
    149 		goto done;
    150 	} else {
    151 		struct mbr_partition *ourdp = NULL;
    152 
    153 		ourdp = mbr_findslice(dp, bp);
    154 		if (ourdp ==  NO_MBR_SIGNATURE)
    155 			goto nombrpart;
    156 
    157 		for (i = 0; i < MBR_PART_COUNT; i++, dp++) {
    158 			/* Install in partition e, f, g, or h. */
    159 			pp = &lp->d_partitions[RAW_PART + 1 + i];
    160 			pp->p_offset = dp->mbrp_start;
    161 			pp->p_size = dp->mbrp_size;
    162 			if (dp->mbrp_type == MBR_PTYPE_LNXEXT2)
    163 				pp->p_fstype = FS_EX2FS;
    164 
    165 			if (dp->mbrp_type == MBR_PTYPE_LNXSWAP)
    166 				pp->p_fstype = FS_SWAP;
    167 
    168 			/* is this ours? */
    169 			if (dp == ourdp) {
    170 				/* need sector address for SCSI/IDE,
    171 				 cylinder for ESDI/ST506/RLL */
    172 				dospartoff = dp->mbrp_start;
    173 				cyl = MBR_PCYL(dp->mbrp_scyl, dp->mbrp_ssect);
    174 
    175 				/* update disklabel with details */
    176 				lp->d_partitions[2].p_size =
    177 				    dp->mbrp_size;
    178 				lp->d_partitions[2].p_offset =
    179 				    dp->mbrp_start;
    180 			}
    181 		}
    182 		lp->d_npartitions = RAW_PART + 1 + i;
    183 	}
    184 
    185 nombrpart:
    186 	/* next, dig out disk label */
    187 	bp->b_blkno = dospartoff + LABELSECTOR;
    188 	bp->b_cylinder = cyl;
    189 	bp->b_bcount = lp->d_secsize;
    190 	bp->b_oflags &= ~(BO_DONE);
    191 	bp->b_flags |= B_READ;
    192 	(*strat)(bp);
    193 
    194 	/* if successful, locate disk label within block and validate */
    195 	if (biowait(bp)) {
    196 		msg = "disk label I/O error";
    197 		goto done;
    198 	}
    199 	for (dlp = (struct disklabel *)bp->b_data;
    200 	    dlp <= (struct disklabel *)((char*)bp->b_data + lp->d_secsize - sizeof(*dlp));
    201 	    dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
    202 		if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) {
    203 			if (msg == NULL)
    204 				msg = "no disk label";
    205 		} else if (dlp->d_npartitions > MAXPARTITIONS ||
    206 			   dkcksum(dlp) != 0)
    207 			msg = "disk label corrupted";
    208 		else {
    209 			*lp = *dlp;
    210 			msg = NULL;
    211 			break;
    212 		}
    213 	}
    214 
    215 done:
    216 	brelse(bp, 0);
    217 	return (msg);
    218 }
    219 
    220 /*
    221  * Write disk label back to device after modification.
    222  */
    223 int
    224 writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp,
    225     struct cpu_disklabel *osdep)
    226 {
    227 	struct mbr_partition *dp;
    228 	struct buf *bp;
    229 	struct disklabel *dlp;
    230 	int error, dospartoff, cyl;
    231 
    232 	/* get a buffer and initialize it */
    233 	bp = geteblk((int)lp->d_secsize);
    234 	bp->b_dev = dev;
    235 
    236 	/* do dos partitions in the process of getting disklabel? */
    237 	dospartoff = 0;
    238 	cyl = LABELSECTOR / lp->d_secpercyl;
    239 	if (!osdep)
    240 		goto nombrpart;
    241 	dp = osdep->dosparts;
    242 
    243 	/* read master boot record */
    244 	bp->b_blkno = MBR_BBSECTOR;
    245 	bp->b_bcount = lp->d_secsize;
    246 	bp->b_flags |= B_READ;
    247 	bp->b_cylinder = MBR_BBSECTOR / lp->d_secpercyl;
    248 	(*strat)(bp);
    249 
    250 	if ((error = biowait(bp)) == 0) {
    251 		struct mbr_partition *ourdp = NULL;
    252 
    253 		ourdp = mbr_findslice(dp, bp);
    254 		if (ourdp ==  NO_MBR_SIGNATURE)
    255 			goto nombrpart;
    256 
    257 		if (ourdp) {
    258 			/* need sector address for SCSI/IDE,
    259 			 cylinder for ESDI/ST506/RLL */
    260 			dospartoff = ourdp->mbrp_start;
    261 			cyl = MBR_PCYL(ourdp->mbrp_scyl, ourdp->mbrp_ssect);
    262 		}
    263 	}
    264 
    265 nombrpart:
    266 	/* next, dig out disk label */
    267 	bp->b_blkno = dospartoff + LABELSECTOR;
    268 	bp->b_cylinder = cyl;
    269 	bp->b_bcount = lp->d_secsize;
    270 	bp->b_oflags &= ~(BO_DONE);
    271 	bp->b_flags |= B_READ;
    272 	(*strat)(bp);
    273 
    274 	/* if successful, locate disk label within block and validate */
    275 	if ((error = biowait(bp)) != 0)
    276 		goto done;
    277 	for (dlp = (struct disklabel *)bp->b_data;
    278 	    dlp <= (struct disklabel *)((char*)bp->b_data + lp->d_secsize - sizeof(*dlp));
    279 	    dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
    280 		if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC &&
    281 		    dkcksum(dlp) == 0) {
    282 			*dlp = *lp;
    283 			bp->b_oflags &= ~(BO_DONE);
    284 			bp->b_flags &= ~(B_READ);
    285 			bp->b_flags |= B_WRITE;
    286 			(*strat)(bp);
    287 			error = biowait(bp);
    288 			goto done;
    289 		}
    290 	}
    291 	error = ESRCH;
    292 
    293 done:
    294 	brelse(bp, 0);
    295 	return (error);
    296 }
    297