xref: /netbsd-src/sys/arch/mipsco/mipsco/disksubr.c (revision 9f4a9600be3013fd256265533fbb085e3c80d678)
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 *
readdisklabel(dev_t dev,void (* strat)(struct buf * bp),register struct disklabel * lp,struct cpu_disklabel * clp)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
writedisklabel(dev_t dev,void (* strat)(struct buf * bp),register struct disklabel * lp,struct cpu_disklabel * clp)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 *
disklabel_mips_to_bsd(struct mips_volheader * vh,struct disklabel * lp)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
disklabel_bsd_to_mips(struct disklabel * lp,struct mips_volheader * vh)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
mipsvh_cksum(struct mips_volheader * vhp)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