xref: /netbsd/sys/arch/luna68k/luna68k/disksubr.c (revision 6550d01e)
1 /* $NetBSD: disksubr.c,v 1.29 2009/10/26 19:16:56 cegger 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  * Credits:
32  * This file was based mostly on the i386/disksubr.c file:
33  *  	@(#)ufs_disksubr.c	7.16 (Berkeley) 5/4/91
34  * The functions: disklabel_sun_to_bsd, disklabel_bsd_to_sun
35  * were originally taken from arch/sparc/scsi/sun_disklabel.c
36  * (which was written by Theo de Raadt) and then substantially
37  * rewritten by Gordon W. Ross.
38  */
39 
40 /*
41  * Copyright (c) 1994 Theo de Raadt.  All rights reserved.
42  *
43  * Redistribution and use in source and binary forms, with or without
44  * modification, are permitted provided that the following conditions
45  * are met:
46  * 1. Redistributions of source code must retain the above copyright
47  *    notice, this list of conditions and the following disclaimer.
48  * 2. Redistributions in binary form must reproduce the above copyright
49  *    notice, this list of conditions and the following disclaimer in the
50  *    documentation and/or other materials provided with the distribution.
51  *
52  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
53  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
54  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
55  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
56  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
57  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
58  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
59  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
60  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
61  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
62  *
63  */
64 
65 /*
66  * Copyright (c) 1994, 1995 Gordon W. Ross
67  *
68  * Redistribution and use in source and binary forms, with or without
69  * modification, are permitted provided that the following conditions
70  * are met:
71  * 1. Redistributions of source code must retain the above copyright
72  *    notice, this list of conditions and the following disclaimer.
73  * 2. Redistributions in binary form must reproduce the above copyright
74  *    notice, this list of conditions and the following disclaimer in the
75  *    documentation and/or other materials provided with the distribution.
76  * 3. All advertising materials mentioning features or use of this software
77  *    must display the following acknowledgement:
78  *	This product includes software developed by the University of
79  *	California, Berkeley and its contributors.
80  * 4. Neither the name of the University nor the names of its contributors
81  *    may be used to endorse or promote products derived from this software
82  *    without specific prior written permission.
83  *
84  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
85  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
86  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
87  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
88  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
89  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
90  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
91  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
92  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
93  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
94  * SUCH DAMAGE.
95  *
96  * Credits:
97  * This file was based mostly on the i386/disksubr.c file:
98  *  	@(#)ufs_disksubr.c	7.16 (Berkeley) 5/4/91
99  * The functions: disklabel_sun_to_bsd, disklabel_bsd_to_sun
100  * were originally taken from arch/sparc/scsi/sun_disklabel.c
101  * (which was written by Theo de Raadt) and then substantially
102  * rewritten by Gordon W. Ross.
103  */
104 
105 #include <sys/cdefs.h>
106 __KERNEL_RCSID(0, "$NetBSD: disksubr.c,v 1.29 2009/10/26 19:16:56 cegger Exp $");
107 
108 #include <sys/param.h>
109 #include <sys/systm.h>
110 #include <sys/buf.h>
111 #include <sys/device.h>
112 #include <sys/disklabel.h>
113 #include <sys/disk.h>
114 #include <sys/dkbad.h>
115 
116 #include <dev/sun/disklabel.h>
117 
118 /*
119  * UniOS disklabel (== ISI disklabel) is very similar to SunOS.
120  *	SunOS				UniOS/ISI
121  *	text		128			128
122  *	(pad)		292			294
123  *	rpm		2		-
124  *	pcyl		2		badchk	2
125  *	sparecyl	2		maxblk	4
126  *	(pad)		4		dtype	2
127  *	interleave	2		ndisk	2
128  *	ncyl		2			2
129  *	acyl		2			2
130  *	ntrack		2			2
131  *	nsect		2			2
132  *	(pad)		4		bhead	2
133  *	-				ppart	2
134  *	dkpart[8]	64			64
135  *	magic		2			2
136  *	cksum		2			2
137  *
138  * Magic number value and checksum calculation are identical.  Subtle
139  * difference is partition start address; UniOS/ISI maintains sector
140  * numbers while SunOS label has cylinder number.
141  *
142  * It is found that LUNA Mach2.5 has BSD label embedded at offset 64
143  * retaining UniOS/ISI label at the end of label block.  LUNA Mach
144  * manipulates BSD disklabel in the same manner as 4.4BSD.  It's
145  * uncertain LUNA Mach can create a disklabel on fresh disks since
146  * Mach writedisklabel logic seems to fail when no BSD label is found.
147  *
148  * Kernel handles disklabel in this way;
149  *	- searchs BSD label at offset 64
150  *	- if not found, searchs UniOS/ISI label at the end of block
151  *	- kernel can distinguish whether it was SunOS label or UniOS/ISI
152  *	  label and understand both
153  *	- kernel writes UniOS/ISI label combined with BSD label to update
154  *	  the label block
155  */
156 
157 #if LABELSECTOR != 0
158 #error	"Default value of LABELSECTOR no longer zero?"
159 #endif
160 
161 static const char *disklabel_om_to_bsd(char *, struct disklabel *);
162 static int disklabel_bsd_to_om(struct disklabel *, char *);
163 
164 /*
165  * Attempt to read a disk label from a device
166  * using the indicated strategy routine.
167  * The label must be partly set up before this:
168  * secpercyl, secsize and anything required for a block i/o read
169  * operation in the driver's strategy/start routines
170  * must be filled in before calling us.
171  *
172  * Return buffer for use in signalling errors if requested.
173  *
174  * Returns null on success and an error string on failure.
175  */
176 const char *
177 readdisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp, struct cpu_disklabel *clp)
178 {
179 	struct buf *bp;
180 	struct disklabel *dlp;
181 	struct sun_disklabel *slp;
182 	int error;
183 
184 	/* minimal requirements for archtypal disk label */
185 	if (lp->d_secperunit == 0)
186 		lp->d_secperunit = 0x1fffffff;
187 	lp->d_npartitions = 1;
188 	if (lp->d_partitions[0].p_size == 0)
189 		lp->d_partitions[0].p_size = 0x1fffffff;
190 	lp->d_partitions[0].p_offset = 0;
191 
192 	/* obtain buffer to probe drive with */
193 	bp = geteblk((int)lp->d_secsize);
194 
195 	/* next, dig out disk label */
196 	bp->b_dev = dev;
197 	bp->b_blkno = LABELSECTOR;
198 	bp->b_cylinder = 0;
199 	bp->b_bcount = lp->d_secsize;
200 	bp->b_flags |= B_READ;
201 	(*strat)(bp);
202 
203 	/* if successful, locate disk label within block and validate */
204 	error = biowait(bp);
205 	if (!error) {
206 		/* Save the whole block in case it has info we need. */
207 		memcpy(clp->cd_block, bp->b_data, sizeof(clp->cd_block));
208 	}
209 	brelse(bp, 0);
210 	if (error)
211 		return ("disk label read error");
212 
213 	/* Check for a NetBSD disk label first. */
214 	dlp = (struct disklabel *)(clp->cd_block + LABELOFFSET);
215 	if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC) {
216 		if (dkcksum(dlp) == 0) {
217 			*lp = *dlp; 	/* struct assignment */
218 			return (NULL);
219 		}
220 		printf("NetBSD disk label corrupted");
221 	}
222 
223 	/* Check for a UniOS/ISI disk label. */
224 	slp = (struct sun_disklabel *)clp->cd_block;
225 	if (slp->sl_magic == SUN_DKMAGIC) {
226 		return (disklabel_om_to_bsd(clp->cd_block, lp));
227 	}
228 
229 	memset(clp->cd_block, 0, sizeof(clp->cd_block));
230 	return ("no disk label");
231 }
232 
233 /*
234  * Check new disk label for sensibility
235  * before setting it.
236  */
237 int
238 setdisklabel(struct disklabel *olp, struct disklabel *nlp, u_long openmask, struct cpu_disklabel *clp)
239 {
240 	struct partition *opp, *npp;
241 	int i;
242 
243 	/* sanity clause */
244 	if ((nlp->d_secpercyl == 0) || (nlp->d_secsize == 0) ||
245 	    (nlp->d_secsize % DEV_BSIZE) != 0)
246 		return (EINVAL);
247 
248 	/* special case to allow disklabel to be invalidated */
249 	if (nlp->d_magic == 0xffffffff) {
250 		*olp = *nlp;
251 		return (0);
252 	}
253 
254 	if (nlp->d_magic != DISKMAGIC ||
255 	    nlp->d_magic2 != DISKMAGIC ||
256 	    dkcksum(nlp) != 0)
257 		return (EINVAL);
258 
259 	while (openmask != 0) {
260 		i = ffs(openmask) - 1;
261 		openmask &= ~(1 << i);
262 		if (nlp->d_npartitions <= i)
263 			return (EBUSY);
264 		opp = &olp->d_partitions[i];
265 		npp = &nlp->d_partitions[i];
266 		if (npp->p_offset != opp->p_offset ||
267 		    npp->p_size < opp->p_size)
268 			return (EBUSY);
269 	}
270 
271 	/* We did not modify the new label, so the checksum is OK. */
272 	*olp = *nlp;
273 	return (0);
274 }
275 
276 
277 /*
278  * Write disk label back to device after modification.
279  * Current label is already in clp->cd_block[]
280  */
281 int
282 writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp, struct cpu_disklabel *clp)
283 {
284 	struct buf *bp;
285 	struct disklabel *dlp;
286 	int error;
287 
288 	/* implant NetBSD disklabel at LABELOFFSET. */
289 	dlp = (struct disklabel *)(clp->cd_block + LABELOFFSET);
290 	*dlp = *lp; 	/* struct assignment */
291 
292 	error = disklabel_bsd_to_om(lp, clp->cd_block);
293 	if (error)
294 		return (error);
295 
296 	/* Get a buffer and copy the new label into it. */
297 	bp = geteblk((int)lp->d_secsize);
298 	memcpy(bp->b_data, clp->cd_block, sizeof(clp->cd_block));
299 
300 	/* Write out the updated label. */
301 	bp->b_dev = dev;
302 	bp->b_blkno = LABELSECTOR;
303 	bp->b_cylinder = 0;
304 	bp->b_bcount = lp->d_secsize;
305 	bp->b_flags |= B_WRITE;
306 	(*strat)(bp);
307 	error = biowait(bp);
308 	brelse(bp, 0);
309 
310 	return (error);
311 }
312 
313 /************************************************************************
314  *
315  * The rest of this was taken from arch/sparc/scsi/sun_disklabel.c
316  * and then substantially rewritten by Gordon W. Ross
317  *
318  ************************************************************************/
319 
320 /* What partition types to assume for Sun disklabels: */
321 static u_char
322 sun_fstypes[8] = {
323 	FS_BSDFFS,	/* a */
324 	FS_SWAP,	/* b */
325 	FS_OTHER,	/* c - whole disk */
326 	FS_BSDFFS,	/* d */
327 	FS_BSDFFS,	/* e */
328 	FS_BSDFFS,	/* f */
329 	FS_BSDFFS,	/* g */
330 	FS_BSDFFS,	/* h */
331 };
332 
333 /*
334  * Given a UniOS/ISI disk label, set lp to a BSD disk label.
335  * Returns NULL on success, else an error string.
336  *
337  * The BSD label is cleared out before this is called.
338  */
339 static const char *
340 disklabel_om_to_bsd(char *cp, struct disklabel *lp)
341 {
342 	struct sun_disklabel *sl;
343 	struct partition *npp;
344 	struct sun_dkpart *spp;
345 	int i, secpercyl;
346 	u_short cksum, *sp1, *sp2;
347 
348 	sl = (struct sun_disklabel *)cp;
349 
350 	/* Verify the XOR check. */
351 	sp1 = (u_short *)sl;
352 	sp2 = (u_short *)(sl + 1);
353 	cksum = 0;
354 	while (sp1 < sp2)
355 		cksum ^= *sp1++;
356 	if (cksum != 0)
357 		return ("UniOS disk label, bad checksum");
358 
359 	memset((void *)lp, 0, sizeof(struct disklabel));
360 	/* Format conversion. */
361 	lp->d_magic = DISKMAGIC;
362 	lp->d_magic2 = DISKMAGIC;
363 	memcpy(lp->d_packname, sl->sl_text, sizeof(lp->d_packname));
364 
365 	lp->d_type	 = DTYPE_SCSI;
366 	lp->d_secsize	 = 512;
367 	lp->d_nsectors   = sl->sl_nsectors;
368 	lp->d_ntracks    = sl->sl_ntracks;
369 	lp->d_ncylinders = sl->sl_ncylinders;
370 
371 	secpercyl = sl->sl_nsectors * sl->sl_ntracks;
372 	lp->d_secpercyl  = secpercyl;
373 	lp->d_secperunit = secpercyl * sl->sl_ncylinders;
374 
375 	lp->d_sparespercyl = 0;				/* no way to know */
376 	lp->d_acylinders   = sl->sl_acylinders;
377 	lp->d_rpm          = sl->sl_rpm;		/* UniOS - (empty) */
378 	lp->d_interleave   = sl->sl_interleave;		/* UniOS - ndisk */
379 
380 	if (sl->sl_rpm == 0) {
381 		/* UniOS label has blkoffset, not cyloffset */
382 		secpercyl = 1;
383 	}
384 
385 	lp->d_npartitions = 8;
386 	/* These are as defined in <ufs/ffs/fs.h> */
387 	lp->d_bbsize = 8192;				/* XXX */
388 	lp->d_sbsize = 8192;				/* XXX */
389 	for (i = 0; i < 8; i++) {
390 		spp = &sl->sl_part[i];
391 		npp = &lp->d_partitions[i];
392 		npp->p_offset = spp->sdkp_cyloffset * secpercyl;
393 		npp->p_size = spp->sdkp_nsectors;
394 		if (npp->p_size == 0)
395 			npp->p_fstype = FS_UNUSED;
396 		else {
397 			/* Partition has non-zero size.  Set type, etc. */
398 			npp->p_fstype = sun_fstypes[i];
399 
400 			/*
401 			 * The sun label does not store the FFS fields,
402 			 * so just set them with default values here.
403 			 * XXX: This keeps newfs from trying to rewrite
404 			 * XXX: the disk label in the most common case.
405 			 * XXX: (Should remove that code from newfs...)
406 			 */
407 			if (npp->p_fstype == FS_BSDFFS) {
408 				npp->p_fsize = 1024;
409 				npp->p_frag = 8;
410 				npp->p_cpg = 16;
411 			}
412 		}
413 	}
414 
415 	/*
416 	 * XXX BandAid XXX
417 	 * UniOS rootfs sits on part c which don't begin at sect 0,
418 	 * and impossible to mount.  Thus, make it usable as part b.
419 	 */
420 	if (sl->sl_rpm == 0 && lp->d_partitions[2].p_offset != 0) {
421 		lp->d_partitions[1] = lp->d_partitions[2];
422 		lp->d_partitions[1].p_fstype = FS_BSDFFS;
423 	}
424 
425 	lp->d_checksum = dkcksum(lp);
426 
427 	return (NULL);
428 }
429 
430 /*
431  * Given a BSD disk label, update the UniOS disklabel
432  * pointed to by cp with the new info.  Note that the
433  * UniOS disklabel may have other info we need to keep.
434  * Returns zero or error code.
435  */
436 static int
437 disklabel_bsd_to_om(struct disklabel *lp, char *cp)
438 {
439 	struct sun_disklabel *sl;
440 	struct partition *npp;
441 	struct sun_dkpart *spp;
442 	int i;
443 	u_short cksum, *sp1, *sp2;
444 
445 	if (lp->d_secsize != 512)
446 		return (EINVAL);
447 
448 	sl = (struct sun_disklabel *)cp;
449 
450 	/* Format conversion. */
451 	memcpy(sl->sl_text, lp->d_packname, sizeof(lp->d_packname));
452 	sl->sl_rpm = 0;					/* UniOS */
453 #if 0 /* leave as was */
454 	sl->sl_pcyl = lp->d_ncylinders + lp->d_acylinders;	/* XXX */
455 	sl->sl_sparespercyl = lp->d_sparespercyl;
456 #endif
457 	sl->sl_interleave   = lp->d_interleave;
458 	sl->sl_ncylinders   = lp->d_ncylinders;
459 	sl->sl_acylinders   = lp->d_acylinders;
460 	sl->sl_ntracks      = lp->d_ntracks;
461 	sl->sl_nsectors     = lp->d_nsectors;
462 
463 	for (i = 0; i < 8; i++) {
464 		spp = &sl->sl_part[i];
465 		npp = &lp->d_partitions[i];
466 
467 		spp->sdkp_cyloffset = npp->p_offset;	/* UniOS */
468 		spp->sdkp_nsectors = npp->p_size;
469 	}
470 	sl->sl_magic = SUN_DKMAGIC;
471 
472 	/* Correct the XOR check. */
473 	sp1 = (u_short *)sl;
474 	sp2 = (u_short *)(sl + 1);
475 	sl->sl_cksum = cksum = 0;
476 	while (sp1 < sp2)
477 		cksum ^= *sp1++;
478 	sl->sl_cksum = cksum;
479 
480 	return (0);
481 }
482