1 /* $NetBSD: rdb.c,v 1.3 2021/05/17 20:21:05 mrg 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/libkern/libkern.h>
35 #include <lib/libsa/stand.h>
36
37 #include "rdb.h"
38
39
40 static u_long
rdbchksum(void * bdata)41 rdbchksum(void *bdata)
42 {
43 u_long *blp, cnt, val;
44
45 blp = bdata;
46 cnt = blp[1];
47 val = 0;
48
49 while (cnt--)
50 val += *blp++;
51 return val;
52 }
53
54
55 static struct adostype
getadostype(u_long dostype)56 getadostype(u_long dostype)
57 {
58 struct adostype adt;
59 u_long t3, b1;
60
61 t3 = dostype & 0xffffff00;
62 b1 = dostype & 0x000000ff;
63
64 adt.fstype = b1;
65
66 switch (t3) {
67 case DOST_NBR:
68 adt.archtype = ADT_NETBSDROOT;
69 return adt;
70 case DOST_NBS:
71 adt.archtype = ADT_NETBSDSWAP;
72 return adt;
73 case DOST_NBU:
74 adt.archtype = ADT_NETBSDUSER;
75 return adt;
76 case DOST_AMIX:
77 adt.archtype = ADT_AMIX;
78 if (b1 == 2)
79 adt.fstype = FS_BSDFFS;
80 else
81 adt.fstype = FS_UNUSED;
82 return adt;
83 case DOST_XXXBSD:
84 if (b1 == 'S') {
85 dostype = DOST_NBS;
86 dostype |= FS_SWAP;
87 } else {
88 if (b1 == 'R')
89 dostype = DOST_NBR;
90 else
91 dostype = DOST_NBU;
92 dostype |= FS_BSDFFS;
93 }
94 return getadostype(dostype);
95 case DOST_EXT2:
96 adt.archtype = ADT_EXT2;
97 adt.fstype = FS_EX2FS;
98 return adt;
99 case DOST_RAID:
100 adt.archtype = ADT_RAID;
101 adt.fstype = FS_RAID;
102 return adt;
103 case DOST_MSD:
104 adt.archtype = ADT_MSD;
105 adt.fstype = FS_MSDOS;
106 return adt;
107 default:
108 adt.archtype = ADT_UNKNOWN;
109 adt.fstype = FS_UNUSED;
110 return adt;
111 }
112 }
113
114
115 /*
116 * Find a valid RDB disklabel.
117 */
118 int
search_rdb_label(struct of_dev * devp,char * buf,struct disklabel * lp)119 search_rdb_label(struct of_dev *devp, char *buf, struct disklabel *lp)
120 {
121 struct adostype adt;
122 struct rdblock *rbp;
123 struct partblock *pbp;
124 struct disklabel *dlp;
125 struct partition *pp;
126 u_long blk;
127 size_t read;
128 int i;
129
130 /*
131 * Scan the first RDB_MAXBLOCKS of a disk for an RDB block.
132 */
133 rbp = (struct rdblock *)buf;
134 for (blk = 0; blk < RDB_MAXBLOCKS; blk++) {
135 if (strategy(devp, F_READ, blk, DEV_BSIZE, buf, &read)
136 || read != DEV_BSIZE)
137 return ERDLAB;
138
139 /* check for valid RDB */
140 if (rbp->id == RDBLOCK_ID && rdbchksum(rbp) == 0)
141 break;
142
143 /* check for native NetBSD label */
144 dlp = (struct disklabel *)(buf + LABELOFFSET);
145 if (dlp->d_magic == DISKMAGIC && dkcksum(dlp) == 0) {
146 *lp = *dlp;
147 return 0;
148 }
149 }
150 if (blk == RDB_MAXBLOCKS)
151 return ERDLAB;
152
153 /* Found RDB, clear disklabel partitions before reading PART blocks. */
154 lp->d_npartitions = RAW_PART + 1;
155 for (i = 0; i < MAXPARTITIONS; i++) {
156 lp->d_partitions[i].p_size = 0;
157 lp->d_partitions[i].p_offset = 0;
158 lp->d_partitions[i].p_fstype = 0;
159 }
160
161 /*
162 * Construct a disklabel from RDB.
163 */
164 lp->d_secsize = rbp->nbytes;
165 lp->d_nsectors = rbp->nsectors;
166 lp->d_ntracks = rbp->nheads;
167 /* be prepared that rbp->ncylinders may be a bogus value */
168 if (rbp->highcyl == 0)
169 lp->d_ncylinders = rbp->ncylinders;
170 else
171 lp->d_ncylinders = rbp->highcyl + 1;
172 /* also don't trust rbp->secpercyl */
173 lp->d_secpercyl = (rbp->secpercyl <= lp->d_nsectors * lp->d_ntracks) ?
174 rbp->secpercyl : lp->d_nsectors * lp->d_ntracks;
175 if (lp->d_secpercyl == 0)
176 lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
177
178 lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders;
179 lp->d_acylinders = rbp->ncylinders - (rbp->highcyl - rbp->lowcyl + 1);
180 lp->d_rpm = 3600;
181 lp->d_interleave = rbp->interleave;
182 lp->d_headswitch = lp->d_flags = lp->d_trackskew = lp->d_cylskew = 0;
183 lp->d_trkseek = 0;
184
185 /* raw partition gets the entire disk */
186 lp->d_partitions[RAW_PART].p_size = rbp->ncylinders * lp->d_secpercyl;
187
188 /*
189 * Now scan for partition blocks.
190 */
191 pbp = (struct partblock *)buf;
192 for (blk = rbp->partbhead; blk != RDBNULL; blk = pbp->next) {
193 if (strategy(devp, F_READ, blk * (lp->d_secsize / DEV_BSIZE),
194 lp->d_secsize, buf, &read)
195 || read != lp->d_secsize)
196 return ERDLAB;
197
198 /* verify ID and checksum of PART block */
199 if (pbp->id != PARTBLOCK_ID || rdbchksum(pbp))
200 return ERDLAB;
201
202 /* environment table in PART block needs at least 11 entries */
203 if (pbp->e.tabsize < 11)
204 return ERDLAB;
205
206 /* need a table size of 16 for a valid dostype */
207 if (pbp->e.tabsize < 16)
208 pbp->e.dostype = 0;
209 adt = getadostype(pbp->e.dostype);
210
211 /* determine partition index */
212 switch (adt.archtype) {
213 case ADT_NETBSDROOT:
214 pp = &lp->d_partitions[0];
215 if (pp->p_size)
216 continue;
217 break;
218 case ADT_NETBSDSWAP:
219 pp = &lp->d_partitions[1];
220 if (pp->p_size)
221 continue;
222 break;
223 default:
224 pp = &lp->d_partitions[lp->d_npartitions++];
225 break;
226 }
227
228 /* sort partitions after RAW_PART by offset */
229 while ((pp - lp->d_partitions) > RAW_PART + 1) {
230 daddr_t boff;
231
232 boff = pbp->e.lowcyl * pbp->e.secpertrk
233 * pbp->e.numheads
234 * ((pbp->e.sizeblock << 2) / lp->d_secsize);
235 if (boff > (pp - 1)->p_offset)
236 break;
237 *pp = *(pp - 1); /* struct copy */
238 pp--;
239 }
240
241 /* get partition size, offset, fstype */
242 pp->p_size = (pbp->e.highcyl - pbp->e.lowcyl + 1)
243 * pbp->e.secpertrk * pbp->e.numheads
244 * ((pbp->e.sizeblock << 2) / lp->d_secsize);
245 pp->p_offset = pbp->e.lowcyl * pbp->e.secpertrk
246 * pbp->e.numheads
247 * ((pbp->e.sizeblock << 2) / lp->d_secsize);
248 pp->p_fstype = adt.fstype;
249 }
250
251 /*
252 * All partitions have been found. The disklabel is valid.
253 */
254 lp->d_magic = lp->d_magic2 = DISKMAGIC;
255 lp->d_checksum = 0;
256 lp->d_checksum = dkcksum(lp);
257 return 0;
258 }
259