xref: /netbsd/sys/arch/arm/arm/disksubr_acorn.c (revision bf9ec67e)
1 /*	$NetBSD: disksubr_acorn.c,v 1.1 2001/03/04 05:06:51 matt Exp $	*/
2 
3 /*
4  * Copyright (c) 1998 Christopher G. Demetriou.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *      This product includes software developed by Christopher G. Demetriou
17  *	for the NetBSD Project.
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*
34  * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
35  * Copyright (c) 1995 Mark Brinicombe
36  * All rights reserved.
37  *
38  * Redistribution and use in source and binary forms, with or without
39  * modification, are permitted provided that the following conditions
40  * are met:
41  * 1. Redistributions of source code must retain the above copyright
42  *    notice, this list of conditions and the following disclaimer.
43  * 2. Redistributions in binary form must reproduce the above copyright
44  *    notice, this list of conditions and the following disclaimer in the
45  *    documentation and/or other materials provided with the distribution.
46  * 3. All advertising materials mentioning features or use of this software
47  *    must display the following acknowledgement:
48  *	This product includes software developed by the University of
49  *	California, Berkeley and its contributors.
50  * 4. Neither the name of the University nor the names of its contributors
51  *    may be used to endorse or promote products derived from this software
52  *    without specific prior written permission.
53  *
54  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
55  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
58  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
59  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
60  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
62  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
63  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64  * SUCH DAMAGE.
65  *
66  *	from: @(#)ufs_disksubr.c	7.16 (Berkeley) 5/4/91
67  */
68 
69 #include <sys/param.h>
70 #include <sys/systm.h>
71 #include <sys/buf.h>
72 #include <sys/disklabel.h>
73 
74 static int filecore_checksum __P((u_char *));
75 
76 /*
77  * static int filecore_checksum(u_char *bootblock)
78  *
79  * Calculates the filecore boot block checksum. This is used to validate
80  * a filecore boot block on the disk.  If a boot block is validated then
81  * it is used to locate the partition table. If the boot block is not
82  * validated, it is assumed that the whole disk is NetBSD.
83  *
84  * The basic algorithm is:
85  *
86  *	for (each byte in block, excluding checksum) {
87  *		sum += byte;
88  *		if (sum > 255)
89  *			sum -= 255;
90  *	}
91  *
92  * That's equivalent to summing all of the bytes in the block
93  * (excluding the checksum byte, of course), then calculating the
94  * checksum as "cksum = sum - ((sum - 1) / 255) * 255)".  That
95  * expression may or may not yield a faster checksum function,
96  * but it's easier to reason about.
97  *
98  * Note that if you have a block filled with bytes of a single
99  * value "X" (regardless of that value!) and calculate the cksum
100  * of the block (excluding the checksum byte), you will _always_
101  * end up with a checksum of X.  (Do the math; that can be derived
102  * from the checksum calculation function!)  That means that
103  * blocks which contain bytes which all have the same value will
104  * always checksum properly.  That's a _very_ unlikely occurence
105  * (probably impossible, actually) for a valid filecore boot block,
106  * so we treat such blocks as invalid.
107  */
108 static int
109 filecore_checksum(bootblock)
110 	u_char *bootblock;
111 {
112 	u_char byte0, accum_diff;
113 	u_int sum;
114 	int i;
115 
116 	sum = 0;
117 	accum_diff = 0;
118 	byte0 = bootblock[0];
119 
120 	/*
121 	 * Sum the contents of the block, keeping track of whether
122 	 * or not all bytes are the same.  If 'accum_diff' ends up
123 	 * being zero, all of the bytes are, in fact, the same.
124 	 */
125 	for (i = 0; i < 511; ++i) {
126 		sum += bootblock[i];
127 		accum_diff |= bootblock[i] ^ byte0;
128 	}
129 
130 	/*
131 	 * Check to see if the checksum byte is the same as the
132 	 * rest of the bytes, too.  (Note that if all of the bytes
133 	 * are the same except the checksum, a checksum compare
134 	 * won't succeed, but that's not our problem.)
135 	 */
136 	accum_diff |= bootblock[i] ^ byte0;
137 
138 	/* All bytes in block are the same; call it invalid. */
139 	if (accum_diff == 0)
140 		return (-1);
141 
142 	return (sum - ((sum - 1) / 255) * 255);
143 }
144 
145 
146 int
147 filecore_label_read(dev, strat, lp, osdep, msgp, cylp, netbsd_label_offp)
148 	dev_t dev;
149 	void (*strat) __P((struct buf *));
150 	struct disklabel *lp;
151 	struct cpu_disklabel *osdep;
152 	char **msgp;
153 	int *cylp, *netbsd_label_offp;
154 {
155 	struct filecore_bootblock *bb;
156 	int heads;
157 	int sectors;
158 	int rv = 1;
159 	int cyl, netbsdpartoff;
160 	struct buf *bp;
161 
162 #ifdef __GNUC__
163 	netbsdpartoff = 0;		/* XXX -Wuninitialized */
164 #endif
165 
166 	/* get a buffer and initialize it */
167         bp = geteblk((int)lp->d_secsize);
168         bp->b_dev = dev;
169 
170 	/* read the Acorn filecore boot block */
171 
172 	bp->b_blkno = FILECORE_BOOT_SECTOR;
173 	bp->b_bcount = lp->d_secsize;
174 	bp->b_flags |= B_READ;
175 	bp->b_cylinder = bp->b_blkno / lp->d_secpercyl;
176 	(*strat)(bp);
177 
178 	/*
179 	 * if successful, validate boot block and
180 	 * locate partition table
181 	 */
182 
183 	if (biowait(bp)) {
184 		*msgp = "filecore boot block I/O error";
185 		goto out;
186 	}
187 
188 	bb = (struct filecore_bootblock *)bp->b_data;
189 
190 	/* Validate boot block */
191 
192 	if (bb->checksum != filecore_checksum((u_char *)bb)) {
193 		/*
194 		 * Invalid boot block so lets assume the
195 		 *  entire disc is NetBSD
196 		 */
197 		rv = 0;
198 		goto out;
199 	}
200 
201 	/* Get some information from the boot block */
202 
203 	cyl = bb->partition_cyl_low + (bb->partition_cyl_high << 8);
204 
205 	heads = bb->heads;
206 	sectors = bb->secspertrack;
207 
208 	/* Do we have a NETBSD partition table ? */
209 
210 	if (bb->partition_type == PARTITION_FORMAT_RISCBSD) {
211 /*		printf("heads = %d nsectors = %d\n", heads, sectors);*/
212 		netbsdpartoff = cyl * heads * sectors;
213 	} else if (bb->partition_type == PARTITION_FORMAT_RISCIX) {
214 		struct riscix_partition_table *rpt;
215 		int loop;
216 
217 		/*
218 		 * We have a RISCiX partition table :-( groan
219 		 *
220 		 * Read the RISCiX partition table and see if
221 		 * there is a NetBSD partition
222 		 */
223 
224 		bp->b_blkno = cyl * heads * sectors;
225 /*		printf("Found RiscIX partition table @ %08x\n",
226 		    bp->b_blkno);*/
227 		bp->b_cylinder = bp->b_blkno / lp->d_secpercyl;
228 		bp->b_bcount = lp->d_secsize;
229 		bp->b_flags &= ~(B_DONE);
230 		bp->b_flags |= B_READ;
231 		(*strat)(bp);
232 
233 		/*
234 		 * if successful, locate disk label within block
235 		 * and validate
236 		 */
237 
238 		if (biowait(bp)) {
239 			*msgp = "disk label I/O error";
240 			goto out;
241 		}
242 
243 		rpt = (struct riscix_partition_table *)bp->b_data;
244 /*		for (loop = 0; loop < NRISCIX_PARTITIONS; ++loop)
245 			printf("p%d: %16s %08x %08x %08x\n", loop,
246 			    rpt->partitions[loop].rp_name,
247 			    rpt->partitions[loop].rp_start,
248 			    rpt->partitions[loop].rp_length,
249 			    rpt->partitions[loop].rp_type);
250 */
251 		for (loop = 0; loop < NRISCIX_PARTITIONS; ++loop) {
252 			if (strcmp(rpt->partitions[loop].rp_name,
253 			    "RiscBSD") == 0 ||
254 			    strcmp(rpt->partitions[loop].rp_name,
255 			    "NetBSD") == 0 ||
256 			    strcmp(rpt->partitions[loop].rp_name,
257 			    "Empty:") == 0) {
258 				netbsdpartoff =
259 				    rpt->partitions[loop].rp_start;
260 				break;
261 			}
262 		}
263 		if (loop == NRISCIX_PARTITIONS) {
264 			*msgp = "NetBSD partition identifier string not found.";
265 			goto out;
266 		}
267 	} else {
268 		*msgp = "Invalid partition format";
269 		goto out;
270 	}
271 
272 	*cylp = cyl;
273 	*netbsd_label_offp = netbsdpartoff;
274 	*msgp = NULL;
275 out:
276         brelse(bp);
277 	return (rv);
278 }
279 
280 
281 int
282 filecore_label_locate(dev, strat, lp, osdep, cylp, netbsd_label_offp)
283 	dev_t dev;
284 	void (*strat) __P((struct buf *));
285 	struct disklabel *lp;
286 	struct cpu_disklabel *osdep;
287 	int *cylp, *netbsd_label_offp;
288 {
289 	struct filecore_bootblock *bb;
290 	int heads;
291 	int sectors;
292 	int rv;
293 	int cyl, netbsdpartoff;
294 	struct buf *bp;
295 
296 	/* get a buffer and initialize it */
297         bp = geteblk((int)lp->d_secsize);
298         bp->b_dev = dev;
299 
300 	/* read the filecore boot block */
301 
302 /*	printf("writedisklabel: Reading boot block\n");*/
303 
304 	bp->b_blkno = FILECORE_BOOT_SECTOR;
305 	bp->b_bcount = lp->d_secsize;
306 	bp->b_flags |= B_READ;
307 	bp->b_cylinder = bp->b_blkno / lp->d_secpercyl;
308 	(*strat)(bp);
309 
310 	/*
311 	 * if successful, validate boot block and locate
312 	 * partition table
313 	 */
314 
315 	if ((rv = biowait(bp)) != 0) {
316 		rv = -rv;
317 		goto out;
318 	}
319 
320 	bb = (struct filecore_bootblock *)bp->b_data;
321 	rv = 1;
322 
323 	/* Validate boot block */
324 
325 	if (bb->checksum != filecore_checksum((u_char *)bb)) {
326 		/*
327 		 * Invalid boot block so lets assume the
328 		 * entire disc is NetBSD
329 		 */
330 
331 /*		printf("writedisklabel: Invalid filecore boot block (incorrect checksum)\n");*/
332 		rv = 0;
333 		goto out;
334 	}
335 
336 	/* Do we have a NetBSD partition ? */
337 
338 	if (bb->partition_type != PARTITION_FORMAT_RISCBSD) {
339 		printf("writedisklabel: Invalid partition format\n");
340 		rv = -1;
341 		goto out;
342 	}
343 
344 	cyl = bb->partition_cyl_low + (bb->partition_cyl_high << 8);
345 
346 	heads = bb->heads;
347 	sectors = bb->secspertrack;
348 
349 	/*printf("heads = %d nsectors = %d\n", heads, sectors);*/
350 
351 	netbsdpartoff = cyl * heads * sectors;
352 
353 	*cylp = cyl;
354 	*netbsd_label_offp = netbsdpartoff;
355 out:
356         brelse(bp);
357 	return (rv);
358 }
359