xref: /netbsd-src/sys/arch/ofppc/stand/ofwboot/rdb.c (revision d25ffa98a4bfca1fe272f3c182496ec9934faac7)
1 /*	$NetBSD: rdb.c,v 1.2 2010/06/19 08:48:33 kiyohara Exp $	*/
2 
3 /*-
4  * Copyright (c) 2009 Frank Wille.
5  * All rights reserved.
6  *
7  * Written by Frank Wille for The NetBSD Project.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include <sys/param.h>
32 #include <sys/disklabel_rdb.h>
33 
34 #include <lib/libsa/stand.h>
35 
36 #include "rdb.h"
37 
38 
39 static u_long
40 rdbchksum(void *bdata)
41 {
42 	u_long *blp, cnt, val;
43 
44 	blp = bdata;
45 	cnt = blp[1];
46 	val = 0;
47 
48 	while (cnt--)
49 		val += *blp++;
50 	return val;
51 }
52 
53 
54 static struct adostype
55 getadostype(u_long dostype)
56 {
57 	struct adostype adt;
58 	u_long t3, b1;
59 
60 	t3 = dostype & 0xffffff00;
61 	b1 = dostype & 0x000000ff;
62 
63 	adt.fstype = b1;
64 
65 	switch (t3) {
66 	case DOST_NBR:
67 		adt.archtype = ADT_NETBSDROOT;
68 		return adt;
69 	case DOST_NBS:
70 		adt.archtype = ADT_NETBSDSWAP;
71 		return adt;
72 	case DOST_NBU:
73 		adt.archtype = ADT_NETBSDUSER;
74 		return adt;
75 	case DOST_AMIX:
76 		adt.archtype = ADT_AMIX;
77 		if (b1 == 2)
78 			adt.fstype = FS_BSDFFS;
79 		else
80 			adt.fstype = FS_UNUSED;
81 		return adt;
82 	case DOST_XXXBSD:
83 		if (b1 == 'S') {
84 			dostype = DOST_NBS;
85 			dostype |= FS_SWAP;
86 		} else {
87 			if (b1 == 'R')
88 				dostype = DOST_NBR;
89 			else
90 				dostype = DOST_NBU;
91 			dostype |= FS_BSDFFS;
92 		}
93 		return getadostype(dostype);
94 	case DOST_EXT2:
95 		adt.archtype = ADT_EXT2;
96 		adt.fstype = FS_EX2FS;
97 		return adt;
98 	case DOST_RAID:
99 		adt.archtype = ADT_RAID;
100 		adt.fstype = FS_RAID;
101 		return adt;
102 	case DOST_MSD:
103 		adt.archtype = ADT_MSD;
104 		adt.fstype = FS_MSDOS;
105 		return adt;
106 	default:
107 		adt.archtype = ADT_UNKNOWN;
108 		adt.fstype = FS_UNUSED;
109 		return adt;
110 	}
111 }
112 
113 
114 /*
115  * Find a valid RDB disklabel.
116  */
117 int
118 search_rdb_label(struct of_dev *devp, char *buf, struct disklabel *lp)
119 {
120 	struct adostype adt;
121 	struct rdblock *rbp;
122 	struct partblock *pbp;
123 	struct disklabel *dlp;
124 	struct partition *pp;
125 	u_long blk;
126 	size_t read;
127 	int i;
128 
129 	/*
130 	 * Scan the first RDB_MAXBLOCKS of a disk for an RDB block.
131 	 */
132 	rbp = (struct rdblock *)buf;
133 	for (blk = 0; blk < RDB_MAXBLOCKS; blk++) {
134 		if (strategy(devp, F_READ, blk, DEV_BSIZE, buf, &read)
135 		    || read != DEV_BSIZE)
136 			return ERDLAB;
137 
138 		/* check for valid RDB */
139 		if (rbp->id == RDBLOCK_ID && rdbchksum(rbp) == 0)
140 			break;
141 
142 		/* check for native NetBSD label */
143 		dlp = (struct disklabel *)(buf + LABELOFFSET);
144 		if (dlp->d_magic == DISKMAGIC && dkcksum(dlp) == 0) {
145 			*lp = *dlp;
146 			return 0;
147 		}
148 	}
149 	if (blk == RDB_MAXBLOCKS)
150 		return ERDLAB;
151 
152 	/* Found RDB, clear disklabel partitions before reading PART blocks. */
153 	lp->d_npartitions = RAW_PART + 1;
154 	for (i = 0; i < MAXPARTITIONS; i++) {
155 		lp->d_partitions[i].p_size = 0;
156 		lp->d_partitions[i].p_offset = 0;
157 		lp->d_partitions[i].p_fstype = 0;
158 	}
159 
160 	/*
161 	 * Construct a disklabel from RDB.
162 	 */
163 	lp->d_secsize = rbp->nbytes;
164 	lp->d_nsectors = rbp->nsectors;
165 	lp->d_ntracks = rbp->nheads;
166 	/* be prepared that rbp->ncylinders may be a bogus value */
167 	if (rbp->highcyl == 0)
168 		lp->d_ncylinders = rbp->ncylinders;
169 	else
170 		lp->d_ncylinders = rbp->highcyl + 1;
171 	/* also don't trust rbp->secpercyl */
172 	lp->d_secpercyl = (rbp->secpercyl <= lp->d_nsectors * lp->d_ntracks) ?
173 	    rbp->secpercyl : lp->d_nsectors * lp->d_ntracks;
174 	if (lp->d_secpercyl == 0)
175 		lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
176 
177 	lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders;
178 	lp->d_acylinders = rbp->ncylinders - (rbp->highcyl - rbp->lowcyl + 1);
179 	lp->d_rpm = 3600;
180 	lp->d_interleave = rbp->interleave;
181 	lp->d_headswitch = lp->d_flags = lp->d_trackskew = lp->d_cylskew = 0;
182 	lp->d_trkseek = 0;
183 
184 	/* raw partition gets the entire disk */
185 	lp->d_partitions[RAW_PART].p_size = rbp->ncylinders * lp->d_secpercyl;
186 
187 	/*
188 	 * Now scan for partition blocks.
189 	 */
190 	pbp = (struct partblock *)buf;
191 	for (blk = rbp->partbhead; blk != RDBNULL; blk = pbp->next) {
192 		if (strategy(devp, F_READ, blk * (lp->d_secsize / DEV_BSIZE),
193 		    lp->d_secsize, buf, &read)
194 		    || read != lp->d_secsize)
195 			return ERDLAB;
196 
197 		/* verify ID and checksum of PART block */
198 		if (pbp->id != PARTBLOCK_ID || rdbchksum(pbp))
199 			return ERDLAB;
200 
201 		/* environment table in PART block needs at least 11 entries */
202 		if (pbp->e.tabsize < 11)
203 			return ERDLAB;
204 
205 		/* need a table size of 16 for a valid dostype */
206 		if (pbp->e.tabsize < 16)
207 			pbp->e.dostype = 0;
208 		adt = getadostype(pbp->e.dostype);
209 
210 		/* determine partition index */
211 		switch (adt.archtype) {
212 		case ADT_NETBSDROOT:
213 			pp = &lp->d_partitions[0];
214 			if (pp->p_size)
215 				continue;
216 			break;
217 		case ADT_NETBSDSWAP:
218 			pp = &lp->d_partitions[1];
219 			if (pp->p_size)
220 				continue;
221 			break;
222 		default:
223 			pp = &lp->d_partitions[lp->d_npartitions++];
224 			break;
225 		}
226 
227 		/* sort partitions after RAW_PART by offset */
228 		while ((pp - lp->d_partitions) > RAW_PART + 1) {
229 			daddr_t boff;
230 
231 			boff = pbp->e.lowcyl * pbp->e.secpertrk
232 			    * pbp->e.numheads
233 			    * ((pbp->e.sizeblock << 2) / lp->d_secsize);
234 			if (boff > (pp - 1)->p_offset)
235 				break;
236 			*pp = *(pp - 1);	/* struct copy */
237 			pp--;
238 		}
239 
240 		/* get partition size, offset, fstype */
241 		pp->p_size = (pbp->e.highcyl - pbp->e.lowcyl + 1)
242 		    * pbp->e.secpertrk * pbp->e.numheads
243 		    * ((pbp->e.sizeblock << 2) / lp->d_secsize);
244 		pp->p_offset = pbp->e.lowcyl * pbp->e.secpertrk
245 		    * pbp->e.numheads
246 		    * ((pbp->e.sizeblock << 2) / lp->d_secsize);
247 		pp->p_fstype = adt.fstype;
248 	}
249 
250 	/*
251 	 * All partitions have been found. The disklabel is valid.
252 	 */
253 	lp->d_magic = lp->d_magic2 = DISKMAGIC;
254 	lp->d_checksum = 0;
255 	lp->d_checksum = dkcksum(lp);
256 	return 0;
257 }
258