rdb.c revision 1.1.2.3 1 /* $NetBSD: rdb.c,v 1.1.2.3 2010/08/11 22:52:31 yamt 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