xref: /openbsd-src/sys/arch/luna88k/luna88k/disksubr.c (revision d45ba34c1b79ba115a2541c9bc4453e53c63ff12)
1 /* $OpenBSD: disksubr.c,v 1.65 2024/12/28 00:00:32 aoyama Exp $ */
2 /* $NetBSD: disksubr.c,v 1.12 2002/02/19 17:09:44 wiz Exp $ */
3 
4 /*
5  * Copyright (c) 1994, 1995 Gordon W. Ross
6  * Copyright (c) 1994 Theo de Raadt
7  * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the University of
21  *	California, Berkeley and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  */
38 
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/buf.h>
42 #include <sys/device.h>
43 #include <sys/disklabel.h>
44 #include <sys/disk.h>
45 
46 #include <dev/sun/disklabel.h>
47 
48 /*
49  * UniOS disklabel (== ISI disklabel) is very similar to SunOS.
50  *	SunOS				UniOS/ISI
51  *	text		128			128
52  *	(pad)		292			294
53  *	rpm		2		-
54  *	pcyl		2		badchk	2
55  *	sparecyl	2		maxblk	4
56  *	(pad)		4		dtype	2
57  *	interleave	2		ndisk	2
58  *	ncyl		2			2
59  *	acyl		2			2
60  *	ntrack		2			2
61  *	nsect		2			2
62  *	(pad)		4		bhead	2
63  *	-				ppart	2
64  *	dkpart[8]	64			64
65  *	magic		2			2
66  *	cksum		2			2
67  *
68  * Magic number value and checksum calculation are identical.  Subtle
69  * difference is partition start address; UniOS/ISI maintains sector
70  * numbers while SunOS label has cylinder number.
71  *
72  * It is found that LUNA Mach2.5 has BSD label embedded at offset 64
73  * retaining UniOS/ISI label at the end of label block.  LUNA Mach
74  * manipulates BSD disklabel in the same manner as 4.4BSD.  It's
75  * uncertain LUNA Mach can create a disklabel on fresh disks since
76  * Mach writedisklabel logic seems to fail when no BSD label is found.
77  *
78  * Kernel handles disklabel in this way;
79  *	- searches BSD label at offset 64
80  *	- if not found, searches UniOS/ISI label at the end of block
81  *	- kernel can distinguish whether it was SunOS label or UniOS/ISI
82  *	  label and understand both
83  *	- kernel writes UniOS/ISI label combined with BSD label to update
84  *	  the label block
85  */
86 
87 #if LABELSECTOR != 0
88 #error	"Default value of LABELSECTOR no longer zero?"
89 #endif
90 
91 int disklabel_om_to_bsd(dev_t, struct sun_disklabel *, struct disklabel *);
92 int disklabel_bsd_to_om(struct disklabel *, struct sun_disklabel *);
93 static __inline u_int sun_extended_sum(struct sun_disklabel *, void *);
94 
95 /*
96  * Attempt to read a disk label from a device
97  * using the indicated strategy routine.
98  * The label must be partly set up before this:
99  * secpercyl, secsize and anything required for a block i/o read
100  * operation in the driver's strategy/start routines
101  * must be filled in before calling us.
102  */
103 int
104 readdisklabel(dev_t dev, void (*strat)(struct buf *),
105     struct disklabel *lp, int spoofonly)
106 {
107 	struct sun_disklabel *slp;
108 	struct buf *bp = NULL;
109 	int error;
110 
111 	if ((error = initdisklabel(lp)))
112 		goto done;
113 
114 	/* get a buffer and initialize it */
115 	bp = geteblk(lp->d_secsize);
116 	bp->b_dev = dev;
117 
118 	if (spoofonly)
119 		goto doslabel;
120 
121 	error = readdisksector(bp, strat, lp, DL_BLKTOSEC(lp, LABELSECTOR));
122 	if (error)
123 		goto done;
124 
125 	slp = (struct sun_disklabel *)bp->b_data;
126 	if (slp->sl_magic == SUN_DKMAGIC) {
127 		error = disklabel_om_to_bsd(bp->b_dev, slp, lp);
128 		goto done;
129 	}
130 
131 	error = checkdisklabel(bp->b_dev, bp->b_data + LABELOFFSET, lp, 0,
132 	    DL_GETDSIZE(lp));
133 	if (error == 0)
134 		goto done;
135 
136  doslabel:
137 	error = readdoslabel(bp, strat, lp, NULL, spoofonly);
138 	if (error == 0)
139 		goto done;
140 
141 #if defined(CD9660)
142 	error = iso_disklabelspoof(dev, strat, lp);
143 	if (error == 0)
144 		goto done;
145 #endif
146 #if defined(UDF)
147 	error = udf_disklabelspoof(dev, strat, lp);
148 	if (error == 0)
149 		goto done;
150 #endif
151 
152 done:
153 	if (bp) {
154 		bp->b_flags |= B_INVAL;
155 		brelse(bp);
156 	}
157 	disk_change = 1;
158 	return (error);
159 }
160 
161 /*
162  * Write disk label back to device after modification.
163  */
164 int
165 writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp)
166 {
167 	struct buf *bp = NULL;
168 	int error;
169 
170 	/* get a buffer and initialize it */
171 	bp = geteblk(lp->d_secsize);
172 	bp->b_dev = dev;
173 
174 	error = disklabel_bsd_to_om(lp, (struct sun_disklabel *)bp->b_data);
175 	if (error)
176 		goto done;
177 
178 	/* Write out the updated label. */
179 	bp->b_blkno = LABELSECTOR;
180 	bp->b_bcount = lp->d_secsize;
181 	CLR(bp->b_flags, B_READ | B_WRITE | B_DONE);
182 	SET(bp->b_flags, B_BUSY | B_WRITE | B_RAW);
183 	(*strat)(bp);
184 	error = biowait(bp);
185 
186 done:
187 	if (bp) {
188 		bp->b_flags |= B_INVAL;
189 		brelse(bp);
190 	}
191 	disk_change = 1;
192 	return (error);
193 }
194 
195 /************************************************************************
196  *
197  * The rest of this was taken from arch/sparc/scsi/sun_disklabel.c
198  * and then substantially rewritten by Gordon W. Ross
199  *
200  ************************************************************************/
201 
202 /* What partition types to assume for Sun disklabels: */
203 static const u_char
204 sun_fstypes[16] = {
205 	FS_BSDFFS,	/* a */
206 	FS_SWAP,	/* b */
207 	FS_UNUSED,	/* c - whole disk */
208 	FS_BSDFFS,	/* d */
209 	FS_BSDFFS,	/* e */
210 	FS_BSDFFS,	/* f */
211 	FS_BSDFFS,	/* g */
212 	FS_BSDFFS,	/* h */
213 	FS_BSDFFS,	/* i */
214 	FS_BSDFFS,	/* j */
215 	FS_BSDFFS,	/* k */
216 	FS_BSDFFS,	/* l */
217 	FS_BSDFFS,	/* m */
218 	FS_BSDFFS,	/* n */
219 	FS_BSDFFS,	/* o */
220 	FS_BSDFFS	/* p */
221 };
222 
223 /*
224  * Given a struct sun_disklabel, assume it has an extended partition
225  * table and compute the correct value for sl_xpsum.
226  */
227 static __inline u_int
228 sun_extended_sum(struct sun_disklabel *sl, void *end)
229 {
230 	u_int sum, *xp, *ep;
231 
232 	xp = (u_int *)&sl->sl_xpmag;
233 	ep = (u_int *)end;
234 
235 	sum = 0;
236 	for (; xp < ep; xp++)
237 		sum += *xp;
238 	return (sum);
239 }
240 
241 /*
242  * Given a UniOS/ISI disk label, set lp to a BSD disk label.
243  *
244  * The BSD label is cleared out before this is called.
245  */
246 int
247 disklabel_om_to_bsd(dev_t dev, struct sun_disklabel *sl, struct disklabel *lp)
248 {
249 	struct partition *npp;
250 	struct sun_dkpart *spp;
251 	int i, secpercyl;
252 	u_short cksum = 0, *sp1, *sp2;
253 
254 	/* Verify the XOR check. */
255 	sp1 = (u_short *)sl;
256 	sp2 = (u_short *)(sl + 1);
257 	while (sp1 < sp2)
258 		cksum ^= *sp1++;
259 	if (cksum != 0)
260 		return (EINVAL);	/* UniOS disk label, bad checksum */
261 
262 	/* Format conversion. */
263 	lp->d_magic = DISKMAGIC;
264 	lp->d_magic2 = DISKMAGIC;
265 	memcpy(lp->d_packname, sl->sl_text, sizeof(lp->d_packname));
266 
267 	lp->d_secsize = DEV_BSIZE;
268 	lp->d_nsectors = sl->sl_nsectors;
269 	lp->d_ntracks = sl->sl_ntracks;
270 	lp->d_ncylinders = sl->sl_ncylinders;
271 
272 	secpercyl = sl->sl_nsectors * sl->sl_ntracks;
273 	lp->d_secpercyl = secpercyl;
274 	/* If unset or initialized as full disk, permit refinement */
275 	if (DL_GETDSIZE(lp) == 0 || DL_GETDSIZE(lp) == MAXDISKSIZE)
276 		DL_SETDSIZE(lp, (u_int64_t)secpercyl * sl->sl_ncylinders);
277 	lp->d_version = 1;
278 
279 	memcpy(&lp->d_uid, &sl->sl_uid, sizeof(sl->sl_uid));
280 
281 	lp->d_acylinders = sl->sl_acylinders;
282 
283 	lp->d_npartitions = MAXPARTITIONS;
284 
285 	for (i = 0; i < 8; i++) {
286 		spp = &sl->sl_part[i];
287 		npp = &lp->d_partitions[i];
288 		/* UniOS label uses blkoffset, not cyloffset */
289 		DL_SETPOFFSET(npp, spp->sdkp_cyloffset);
290 		DL_SETPSIZE(npp, spp->sdkp_nsectors);
291 		if (DL_GETPSIZE(npp) == 0) {
292 			npp->p_fstype = FS_UNUSED;
293 		} else {
294 			npp->p_fstype = sun_fstypes[i];
295 			if (npp->p_fstype == FS_BSDFFS) {
296 				/*
297 				 * The sun label does not store the FFS fields,
298 				 * so just set them with default values here.
299 				 */
300 				npp->p_fragblock =
301 				    DISKLABELV1_FFS_FRAGBLOCK(2048, 8);
302 				npp->p_cpg = 16;
303 			}
304 		}
305 	}
306 
307 	/*
308 	 * XXX BandAid XXX
309 	 * UniOS rootfs sits on part c which don't begin at sect 0,
310 	 * and impossible to mount.  Thus, make it usable as part b.
311 	 * XXX how to setup a swap partition on disks shared with UniOS???
312 	 */
313 	if (sl->sl_rpm == 0 && DL_GETPOFFSET(&lp->d_partitions[2]) != 0) {
314 		lp->d_partitions[1] = lp->d_partitions[2];
315 		lp->d_partitions[1].p_fstype = FS_BSDFFS;
316 	}
317 
318 	/* Clear "extended" partition info, tentatively */
319 	for (i = 0; i < SUNXPART; i++) {
320 		npp = &lp->d_partitions[i+8];
321 		DL_SETPOFFSET(npp, 0);
322 		DL_SETPSIZE(npp, 0);
323 		npp->p_fstype = FS_UNUSED;
324 	}
325 
326 	/* Check to see if there's an "extended" partition table
327 	 * SL_XPMAG partitions had checksums up to just before the
328 	 * (new) sl_types variable, while SL_XPMAGTYP partitions have
329 	 * checksums up to the just before the (new) sl_xxx1 variable.
330 	 */
331 	if ((sl->sl_xpmag == SL_XPMAG &&
332 	    sun_extended_sum(sl, &sl->sl_types) == sl->sl_xpsum) ||
333 	    (sl->sl_xpmag == SL_XPMAGTYP &&
334 	    sun_extended_sum(sl, &sl->sl_xxx1) == sl->sl_xpsum)) {
335 		/*
336 		 * There is.  Copy over the "extended" partitions.
337 		 * This code parallels the loop for partitions a-h.
338 		 */
339 		for (i = 0; i < SUNXPART; i++) {
340 			spp = &sl->sl_xpart[i];
341 			npp = &lp->d_partitions[i+8];
342 			DL_SETPOFFSET(npp, spp->sdkp_cyloffset);
343 			DL_SETPSIZE(npp, spp->sdkp_nsectors);
344 			if (DL_GETPSIZE(npp) == 0) {
345 				npp->p_fstype = FS_UNUSED;
346 				continue;
347 			}
348 			npp->p_fstype = sun_fstypes[i+8];
349 			if (npp->p_fstype == FS_BSDFFS) {
350 				npp->p_fragblock =
351 				    DISKLABELV1_FFS_FRAGBLOCK(2048, 8);
352 				npp->p_cpg = 16;
353 			}
354 		}
355 		if (sl->sl_xpmag == SL_XPMAGTYP) {
356 			for (i = 0; i < MAXPARTITIONS; i++) {
357 				npp = &lp->d_partitions[i];
358 				npp->p_fstype = sl->sl_types[i];
359 				npp->p_fragblock = sl->sl_fragblock[i];
360 				npp->p_cpg = sl->sl_cpg[i];
361 			}
362 		}
363 	}
364 
365 	lp->d_checksum = 0;
366 	lp->d_checksum = dkcksum(lp);
367 	return (checkdisklabel(dev, lp, lp, 0, DL_GETDSIZE(lp)));
368 }
369 
370 /*
371  * Given a BSD disk label, update the UniOS disklabel
372  * pointed to by sl with the new info.  Note that the
373  * UniOS disklabel may have other info we need to keep.
374  */
375 int
376 disklabel_bsd_to_om(struct disklabel *lp, struct sun_disklabel *sl)
377 {
378 	struct partition *npp;
379 	struct sun_dkpart *spp;
380 	int i, secpercyl;
381 	u_short cksum, *sp1, *sp2;
382 
383 	if (lp->d_secsize != DEV_BSIZE || lp->d_nsectors == 0 ||
384 	    lp->d_ntracks == 0)
385 		return (EINVAL);
386 
387 	/* Format conversion. */
388 	bzero(sl, sizeof(*sl));
389 	memcpy(sl->sl_text, lp->d_packname, sizeof(lp->d_packname));
390 	sl->sl_rpm = 0;					/* UniOS compatible */
391 #if 0 /* leave as was */
392 	sl->sl_pcylinders = lp->d_ncylinders + lp->d_acylinders; /* XXX */
393 #endif
394 	sl->sl_interleave = 1;
395 	sl->sl_ncylinders = lp->d_ncylinders;
396 	sl->sl_acylinders = lp->d_acylinders;
397 	sl->sl_ntracks = lp->d_ntracks;
398 	sl->sl_nsectors = lp->d_nsectors;
399 
400 	memcpy(&sl->sl_uid, &lp->d_uid, sizeof(lp->d_uid));
401 
402 	for (i = 0; i < 8; i++) {
403 		spp = &sl->sl_part[i];
404 		npp = &lp->d_partitions[i];
405 		spp->sdkp_cyloffset = 0;
406 		spp->sdkp_nsectors = 0;
407 		if (DL_GETPSIZE(npp)) {
408 			spp->sdkp_cyloffset = DL_GETPOFFSET(npp); /* UniOS */
409 			spp->sdkp_nsectors = DL_GETPSIZE(npp);
410 		}
411 	}
412 	sl->sl_magic = SUN_DKMAGIC;
413 
414 	secpercyl = sl->sl_nsectors * sl->sl_ntracks;
415 	for (i = 0; i < SUNXPART; i++) {
416 		spp = &sl->sl_xpart[i];
417 		npp = &lp->d_partitions[i+8];
418 		spp->sdkp_cyloffset = 0;
419 		spp->sdkp_nsectors = 0;
420 		if (DL_GETPSIZE(npp)) {
421 			spp->sdkp_cyloffset = DL_GETPOFFSET(npp);
422 			spp->sdkp_nsectors = DL_GETPSIZE(npp);
423 		}
424 	}
425 	for (i = 0; i < MAXPARTITIONS; i++) {
426 		npp = &lp->d_partitions[i];
427 		sl->sl_types[i] = npp->p_fstype;
428 		sl->sl_fragblock[i] = npp->p_fragblock;
429 		sl->sl_cpg[i] = npp->p_cpg;
430 	}
431 	sl->sl_xpmag = SL_XPMAGTYP;
432 	sl->sl_xpsum = sun_extended_sum(sl, &sl->sl_xxx1);
433 
434 	/* Correct the XOR check. */
435 	sp1 = (u_short *)sl;
436 	sp2 = (u_short *)(sl + 1);
437 	sl->sl_cksum = cksum = 0;
438 	while (sp1 < sp2)
439 		cksum ^= *sp1++;
440 	sl->sl_cksum = cksum;
441 
442 	return (0);
443 }
444