Home | History | Annotate | Line # | Download | only in mipsco
      1 /*	$NetBSD: disksubr.c,v 1.29 2022/05/24 06:28:00 andvar 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  *	@(#)ufs_disksubr.c	7.16 (Berkeley) 5/4/91
     32  */
     33 
     34 #include <sys/cdefs.h>
     35 __KERNEL_RCSID(0, "$NetBSD: disksubr.c,v 1.29 2022/05/24 06:28:00 andvar Exp $");
     36 
     37 #include <sys/param.h>
     38 #include <sys/systm.h>
     39 #include <sys/buf.h>
     40 #include <sys/device.h>
     41 #include <sys/disk.h>
     42 #include <sys/disklabel.h>
     43 #include <sys/syslog.h>
     44 #include <ufs/ufs/dinode.h>		/* XXX for fs.h */
     45 #include <ufs/ffs/fs.h>			/* XXX for BBSIZE & SBSIZE */
     46 
     47 #define	b_cylin	b_resid
     48 
     49 static const char *disklabel_mips_to_bsd(struct mips_volheader *,
     50 					  struct disklabel *);
     51 static int disklabel_bsd_to_mips(struct disklabel *,
     52 					struct mips_volheader *);
     53 static int mipsvh_cksum(struct mips_volheader *);
     54 
     55 #define LABELSIZE(lp)	((char *)&lp->d_partitions[lp->d_npartitions] -	\
     56 			 (char *)lp)
     57 
     58 /*
     59  * Attempt to read a disk label from a device
     60  * using the indicated strategy routine.
     61  * The label must be partly set up before this:
     62  * secpercyl and anything required in the strategy routine
     63  * (e.g., sector size) must be filled in before calling us.
     64  * Returns null on success and an error string on failure.
     65  */
     66 const char *
     67 readdisklabel(dev_t dev, void (*strat)(struct buf *bp), register struct disklabel *lp, struct cpu_disklabel *clp)
     68 {
     69 	register struct buf *bp;
     70 	struct disklabel *dlp;
     71 	struct mips_volheader *mvp;
     72 	int i, err;
     73 
     74 	/* minimum requirements for disk label */
     75 	if (lp->d_secperunit == 0)
     76 		lp->d_secperunit = 0x1fffffff;
     77 	if (lp->d_npartitions == 0) {
     78 		lp->d_npartitions = RAW_PART + 1;
     79 		if (lp->d_partitions[RAW_PART].p_size == 0)
     80 			lp->d_partitions[RAW_PART].p_size = 0x1fffffff;
     81 		lp->d_partitions[RAW_PART].p_offset = 0;
     82 	}
     83 
     84 	bp = geteblk((int)lp->d_secsize);
     85 
     86 	bp->b_dev = dev;
     87 	bp->b_blkno = LABELSECTOR;
     88 	bp->b_bcount = lp->d_secsize;
     89 	bp->b_flags |= B_READ;
     90 	bp->b_cylinder = bp->b_blkno / lp->d_secpercyl;
     91 	(*strat)(bp);
     92 	err = biowait(bp);
     93 	brelse(bp, 0);
     94 
     95 	if (err)
     96 		return "error reading disklabel";
     97 
     98 	/* Check for NetBSD label in second sector */
     99 	dlp = (struct disklabel *)((char *)bp->b_data + LABELOFFSET);
    100 	if (dlp->d_magic == DISKMAGIC)
    101 		if (!dkcksum(dlp)) {
    102 			memcpy(lp, dlp, LABELSIZE(dlp));
    103 			return NULL;	/* NetBSD label found */
    104 		}
    105 
    106 	bp = geteblk((int)lp->d_secsize);
    107 	bp->b_dev = dev;
    108 	bp->b_blkno = MIPS_VHSECTOR;
    109 	bp->b_bcount = lp->d_secsize;
    110 	bp->b_flags |= B_READ;
    111 	bp->b_cylinder = bp->b_blkno / lp->d_secpercyl;
    112 	(*strat)(bp);
    113 	err = biowait(bp);
    114 	brelse(bp, 0);
    115 
    116 	if (err)
    117 		return "error reading volume header";
    118 
    119 	mvp = (struct mips_volheader *)bp->b_data;
    120 	/* Check for MIPS RISC/os volume header */
    121 	if (mvp->vh_magic == MIPS_VHMAGIC)
    122 		return disklabel_mips_to_bsd(mvp, lp);
    123 
    124 	/* Search for NetBSD label in first sector */
    125 	for (i=0; i <= lp->d_secsize - sizeof(*dlp); i += sizeof(long)) {
    126 		dlp = (struct disklabel *) ((char *)mvp + i);
    127 		if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC) {
    128 			if (dlp->d_npartitions > MAXPARTITIONS ||
    129 			    dkcksum(dlp) != 0)
    130 				return "disk label corrupted";
    131 			else {
    132 				memcpy(lp, dlp, sizeof *lp);
    133 				return NULL; /* Found */
    134 			}
    135 		}
    136 	}
    137 	return "no disk label";
    138 }
    139 
    140 /* encoding of disk minor numbers, should be elsewhere... */
    141 #define dkunit(dev)		(minor(dev) >> 3)
    142 #define dkpart(dev)		(minor(dev) & 07)
    143 #define dkminor(unit, part)	(((unit) << 3) | (part))
    144 
    145 /*
    146  * Write disk label back to device after modification.
    147  */
    148 int
    149 writedisklabel(dev_t dev, void (*strat)(struct buf *bp), register struct disklabel *lp, struct cpu_disklabel *clp)
    150 {
    151 	struct buf *bp;
    152 	int labelpart;
    153 	int error;
    154 
    155 	labelpart = dkpart(dev);
    156 	if (lp->d_partitions[labelpart].p_offset != 0) {
    157 		if (lp->d_partitions[0].p_offset != 0)
    158 			return (EXDEV);			/* not quite right */
    159 		labelpart = 0;
    160 	}
    161 
    162 	/* Read RISC/os volume header before merging NetBSD partition info*/
    163 	bp = geteblk((int)lp->d_secsize);
    164 
    165 	bp->b_dev = dev;
    166 	bp->b_blkno = MIPS_VHSECTOR;
    167 	bp->b_bcount = lp->d_secsize;
    168 	bp->b_flags |= B_READ;
    169 	bp->b_cylinder = bp->b_blkno / lp->d_secpercyl;
    170 	(*strat)(bp);
    171 
    172 	if((error = biowait(bp)) != 0)
    173 		goto ioerror;
    174 
    175 	if ((error = disklabel_bsd_to_mips(lp, (void *)bp->b_data)) != 0)
    176 		goto ioerror;
    177 
    178 	/* Write MIPS RISC/os label to first sector */
    179 	bp->b_flags &= ~(B_READ);
    180 	bp->b_oflags &= ~(BO_DONE);
    181 	bp->b_flags |= B_WRITE;
    182 	(*strat)(bp);
    183 	if ((error = biowait(bp)) != 0)
    184 		goto ioerror;
    185 
    186 	/* Write NetBSD disk label to second sector */
    187 	memset(bp->b_data, 0, lp->d_secsize);
    188 	memcpy(bp->b_data, lp, sizeof(*lp));
    189 	bp->b_blkno = LABELSECTOR;
    190 	bp->b_bcount = lp->d_secsize;
    191 	bp->b_cylinder = bp->b_blkno / lp->d_secpercyl;
    192 	bp->b_flags &= ~(B_READ);
    193 	bp->b_oflags &= ~(BO_DONE);
    194 	bp->b_flags |= B_WRITE;
    195 	(*strat)(bp);
    196 	error = biowait(bp);
    197 
    198 ioerror:
    199 	brelse(bp, 0);
    200 	return error;
    201 }
    202 
    203 /*
    204  * Conversion table for mapping partition numbers and types between
    205  * a MIPS volume header and a BSD partition table.
    206  *
    207  * Mips volume header compatibility is required in order to boot
    208  * NetBSD from the Mips stand alone shell, but due to the differences
    209  * in the partition numbers used along with different methods for
    210  * determining partition types we must use a table for mapping the
    211  * differences.
    212  */
    213 
    214 struct partitionmap {
    215 	int	mips_part;		/* Mips partition number */
    216 	int	mips_type;	/* Mips partition type */
    217 	int	bsd_part;		/* BSD partition number */
    218 	int	bsd_type;	/* BSD partition type */
    219 };
    220 
    221 struct partitionmap partition_map[] = {
    222      /* Mips       Mips Type	       BSD      BSD Type */
    223 	{0,	MIPS_FS_BSD42,		0,	FS_BSDFFS},
    224 	{1,	MIPS_FS_BSD42,		1,	FS_SWAP},
    225 	{10,	MIPS_FS_VOLUME,	     RAW_PART,	FS_OTHER},
    226 	{3,	MIPS_FS_BSD42,		3,	FS_BSDFFS},
    227         {4,	MIPS_FS_BSD42,		4,	FS_BSDFFS},
    228         {5,	MIPS_FS_BSD42,		5,	FS_BSDFFS},
    229         {6,	MIPS_FS_BSD42,		6,	FS_BSDFFS},
    230 	{7,	MIPS_FS_BSD42,		7,	FS_BSDFFS}
    231 };
    232 #define NPARTMAP	(sizeof(partition_map)/sizeof(struct partitionmap))
    233 
    234 /*
    235  * Convert a RISC/os disk label into a NetBSD disk label.
    236  *
    237  * Returns NULL on success, otherwise an error string
    238  */
    239 static const char *
    240 disklabel_mips_to_bsd(struct mips_volheader *vh, struct disklabel *lp)
    241 {
    242 	int  i, bp, mp;
    243 	struct partition *lpp;
    244 	if (mipsvh_cksum(vh))
    245 		return ("MIPS disk label corrupted");
    246 
    247 	lp->d_secsize    = vh->vh_dp.dp_secbytes;
    248 	lp->d_nsectors   = vh->vh_dp.dp_secs;
    249 	lp->d_ntracks    = vh->vh_dp.dp_trks0;
    250 	lp->d_ncylinders = vh->vh_dp.dp_cyls;
    251 	lp->d_interleave = vh->vh_dp.dp_interleave;
    252 
    253 	lp->d_secpercyl  = lp->d_nsectors * lp->d_ntracks;
    254 	lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders;
    255 
    256 	lp->d_bbsize = BBSIZE;
    257 	lp->d_sbsize = SBLOCKSIZE;
    258 	lp->d_npartitions = MAXPARTITIONS;
    259 
    260 	for (i = 0; i < NPARTMAP; i++) {
    261 		mp = partition_map[i].mips_part;
    262 		bp = partition_map[i].bsd_part;
    263 
    264 		lpp = &lp->d_partitions[bp];
    265 		lpp->p_offset = vh->vh_part[mp].pt_offset;
    266 		lpp->p_size = vh->vh_part[mp].pt_size;
    267 		lpp->p_fstype = partition_map[i].bsd_type;
    268 		if (lpp->p_fstype == FS_BSDFFS) {
    269 			lpp->p_fsize = 1024;
    270 			lpp->p_frag = 8;
    271 			lpp->p_cpg = 16;
    272 		}
    273 	}
    274 #if DIAGNOSTIC
    275 	printf("Warning: using MIPS disk label\n");
    276 #endif
    277 	return NULL;
    278 }
    279 
    280 /*
    281  * Convert a NetBSD disk label into a RISC/os disk label.
    282  *
    283  * Returns NULL on success, otherwise an error string
    284  */
    285 static int
    286 disklabel_bsd_to_mips(struct disklabel *lp, struct mips_volheader *vh)
    287 {
    288 	int  i, bp, mp;
    289 	struct partition *lpp;
    290 
    291 	if (vh->vh_magic != MIPS_VHMAGIC || mipsvh_cksum(vh) != 0) {
    292 #if DIAGNOSTIC
    293 		printf("Warning: writing MIPS compatible label\n");
    294 #endif
    295 		memset((void *)vh, 0, sizeof *vh);
    296 		vh->vh_magic = MIPS_VHMAGIC;
    297 		vh->vh_root = 0;	/* a*/
    298 		vh->vh_swap = 1;	/* b*/
    299 	}
    300 	strcpy(vh->bootfile, "/netbsd");
    301 	vh->vh_dp.dp_skew = lp->d_trackskew;
    302 	vh->vh_dp.dp_gap1 = 1; /* XXX */
    303 	vh->vh_dp.dp_gap2 = 1; /* XXX */
    304 	vh->vh_dp.dp_cyls = lp->d_ncylinders;
    305 	vh->vh_dp.dp_shd0 = 0;
    306 	vh->vh_dp.dp_trks0 = lp->d_ntracks;
    307 	vh->vh_dp.dp_secs = lp->d_nsectors;
    308 	vh->vh_dp.dp_secbytes = lp->d_secsize;
    309 	vh->vh_dp.dp_interleave = lp->d_interleave;
    310 	vh->vh_dp.dp_nretries = 22;
    311 
    312 	for (i = 0; i < NPARTMAP; i++) {
    313 		mp = partition_map[i].mips_part;
    314 		bp = partition_map[i].bsd_part;
    315 
    316 		lpp = &lp->d_partitions[bp];
    317 		vh->vh_part[mp].pt_offset = lpp->p_offset;
    318 		vh->vh_part[mp].pt_size = lpp->p_size;
    319 		vh->vh_part[mp].pt_fstype = partition_map[i].mips_type;
    320 	}
    321 	/*
    322 	 * Create a fake partition for bootstrap code (or SASH)
    323 	 */
    324 	vh->vh_part[8].pt_offset = 0;
    325 	vh->vh_part[8].pt_size = vh->vh_part[vh->vh_root].pt_offset +
    326 		BBSIZE / vh->vh_dp.dp_secbytes;
    327 	vh->vh_part[8].pt_fstype = MIPS_FS_VOLHDR;
    328 
    329 	vh->vh_cksum = 0;
    330 	vh->vh_cksum = -mipsvh_cksum(vh);
    331 	return 0;
    332 }
    333 
    334 /*
    335  * Compute checksum for MIPS disk volume header
    336  *
    337  * Mips volume header checksum is the 32bit 2's complement sum
    338  * of the entire volume header structure
    339  */
    340 int
    341 mipsvh_cksum(struct mips_volheader *vhp)
    342 {
    343 	int i, *ptr;
    344 	int cksum = 0;
    345 
    346 	ptr = (int *)vhp;
    347 	i = sizeof(*vhp) / sizeof(*ptr);
    348 	while (i--)
    349 		cksum += *ptr++;
    350 	return cksum;
    351 }
    352