1 /* $NetBSD: disksubr.c,v 1.25 2014/04/25 20:17:28 martin 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 * All rights reserved.
36 *
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
39 * are met:
40 * 1. Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in the
44 * documentation and/or other materials provided with the distribution.
45 * 3. Neither the name of the University nor the names of its contributors
46 * may be used to endorse or promote products derived from this software
47 * without specific prior written permission.
48 *
49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 * SUCH DAMAGE.
60 *
61 * from: @(#)ufs_disksubr.c 7.16 (Berkeley) 5/4/91
62 */
63
64 /*
65 * Copyright (c) 1995 Mark Brinicombe
66 * All rights reserved.
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 * from: @(#)ufs_disksubr.c 7.16 (Berkeley) 5/4/91
97 */
98
99 #include <sys/cdefs.h>
100 __KERNEL_RCSID(0, "$NetBSD: disksubr.c,v 1.25 2014/04/25 20:17:28 martin Exp $");
101
102 #include <sys/param.h>
103 #include <sys/systm.h>
104 #include <sys/buf.h>
105 #include <sys/dkbad.h>
106 #include <sys/disklabel.h>
107 #include <sys/syslog.h>
108 #include <sys/device.h>
109 #include <sys/disk.h>
110
111 /*
112 * Attempt to read a disk label from a device
113 * using the indicated strategy routine.
114 * The label must be partly set up before this:
115 * secpercyl, secsize and anything required for a block i/o read
116 * operation in the driver's strategy/start routines
117 * must be filled in before calling us.
118 *
119 * If dos partition table requested, attempt to load it and
120 * find disklabel inside a DOS partition. Also, if bad block
121 * table needed, attempt to extract it as well. Return buffer
122 * for use in signalling errors if requested.
123 *
124 * Returns null on success and an error string on failure.
125 */
126
127 const char *
readdisklabel(dev_t dev,void (* strat)(struct buf *),struct disklabel * lp,struct cpu_disklabel * osdep)128 readdisklabel(dev_t dev, void (*strat)(struct buf *),
129 struct disklabel *lp, struct cpu_disklabel *osdep)
130 {
131 struct buf *bp;
132 struct disklabel *dlp;
133 const char *msg = NULL;
134 int cyl, netbsdpartoff, i, found = 0;
135
136 /* minimal requirements for archtypal disk label */
137
138 if (lp->d_secsize == 0)
139 lp->d_secsize = DEV_BSIZE;
140
141 if (lp->d_secperunit == 0)
142 lp->d_secperunit = 0x1fffffff;
143
144 if (lp->d_npartitions < RAW_PART + 1)
145 lp->d_npartitions = RAW_PART + 1;
146
147 if (lp->d_partitions[RAW_PART].p_size == 0) {
148 lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
149 lp->d_partitions[RAW_PART].p_offset = 0;
150 lp->d_partitions[RAW_PART].p_size = 0x1fffffff;
151 }
152 /*
153 * Set partition 'a' to be the whole disk.
154 * Cleared if we find a netbsd label.
155 */
156 lp->d_partitions[0].p_size = lp->d_partitions[RAW_PART].p_size;
157 lp->d_partitions[0].p_fstype = FS_BSDFFS;
158
159 /* obtain buffer to probe drive with */
160
161 bp = geteblk((int)lp->d_secsize);
162
163 /* request no partition relocation by driver on I/O operations */
164
165 bp->b_dev = dev;
166
167 /* do netbsd partitions in the process of getting disklabel? */
168
169 netbsdpartoff = 0;
170 cyl = LABELSECTOR / lp->d_secpercyl;
171
172 if (osdep) {
173 if (filecore_label_read(dev, strat,lp, osdep, &msg, &cyl,
174 &netbsdpartoff) ||
175 mbr_label_read(dev, strat, lp, osdep, &msg, &cyl,
176 &netbsdpartoff)) {
177 if (msg != NULL)
178 goto done;
179 } else {
180 /*
181 * We didn't find anything we like; NetBSD native.
182 * netbsdpartoff and cyl should be unchanged.
183 */
184 KASSERT(netbsdpartoff == 0);
185 KASSERT(cyl == (LABELSECTOR / lp->d_secpercyl));
186 }
187 }
188
189 /* next, dig out disk label */
190
191 bp->b_blkno = netbsdpartoff + LABELSECTOR;
192 bp->b_cylinder = bp->b_blkno / lp->d_secpercyl;
193 bp->b_bcount = lp->d_secsize;
194 bp->b_flags |= B_READ;
195 (*strat)(bp);
196
197 /* if successful, locate disk label within block and validate */
198
199 if (biowait(bp)) {
200 msg = "disk label I/O error";
201 goto done;
202 }
203 for (dlp = (struct disklabel *)bp->b_data;
204 dlp <= (struct disklabel *)((char *)bp->b_data + lp->d_secsize
205 - sizeof(*dlp));
206 dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
207 if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) {
208 continue;
209 } else if (dlp->d_npartitions > MAXPARTITIONS ||
210 dkcksum(dlp) != 0)
211 msg = "disk label corrupted";
212 else {
213 *lp = *dlp;
214 msg = NULL;
215 found = 1;
216 break;
217 }
218 }
219
220 if (msg != NULL || found == 0)
221 goto done;
222
223 /* obtain bad sector table if requested and present */
224 if (osdep && (lp->d_flags & D_BADSECT)) {
225 struct dkbad *bdp = &osdep->bad;
226 struct dkbad *db;
227
228 i = 0;
229 do {
230 /* read a bad sector table */
231 bp->b_oflags &= ~(BO_DONE);
232 bp->b_flags |= B_READ;
233 bp->b_blkno = lp->d_secperunit - lp->d_nsectors + i;
234 if (lp->d_secsize > DEV_BSIZE)
235 bp->b_blkno *= lp->d_secsize / DEV_BSIZE;
236 else
237 bp->b_blkno /= DEV_BSIZE / lp->d_secsize;
238 bp->b_bcount = lp->d_secsize;
239 bp->b_cylinder = lp->d_ncylinders - 1;
240 (*strat)(bp);
241
242 /* if successful, validate, otherwise try another */
243 if (biowait(bp)) {
244 msg = "bad sector table I/O error";
245 } else {
246 db = (struct dkbad *)(bp->b_data);
247 #define DKBAD_MAGIC 0x4321
248 if (db->bt_mbz == 0
249 && db->bt_flag == DKBAD_MAGIC) {
250 msg = NULL;
251 *bdp = *db;
252 break;
253 } else
254 msg = "bad sector table corrupted";
255 }
256 } while (bp->b_error != 0 && (i += 2) < 10 &&
257 i < lp->d_nsectors);
258 }
259
260 done:
261 brelse(bp, 0);
262 return (msg);
263 }
264
265
266 /*
267 * Check new disk label for sensibility
268 * before setting it.
269 */
270
271 int
setdisklabel(struct disklabel * olp,struct disklabel * nlp,u_long openmask,struct cpu_disklabel * osdep)272 setdisklabel(struct disklabel *olp, struct disklabel *nlp, u_long openmask,
273 struct cpu_disklabel *osdep)
274 {
275 int i;
276 struct partition *opp, *npp;
277
278 /* sanity clause */
279
280 if (nlp->d_secpercyl == 0 || nlp->d_secsize == 0
281 || (nlp->d_secsize % DEV_BSIZE) != 0)
282 return(EINVAL);
283
284 /* special case to allow disklabel to be invalidated */
285
286 if (nlp->d_magic == 0xffffffff) {
287 *olp = *nlp;
288 return (0);
289 }
290
291 if (nlp->d_magic != DISKMAGIC || nlp->d_magic2 != DISKMAGIC
292 || dkcksum(nlp) != 0)
293 return (EINVAL);
294
295 /* XXX add check if other acorn/dos partitions will be overwritten */
296
297 while (openmask != 0) {
298 i = ffs(openmask) - 1;
299 openmask &= ~(1 << i);
300 if (nlp->d_npartitions <= i)
301 return (EBUSY);
302 opp = &olp->d_partitions[i];
303 npp = &nlp->d_partitions[i];
304 if (npp->p_offset != opp->p_offset || npp->p_size < opp->p_size)
305 return (EBUSY);
306 /*
307 * Copy internally-set partition information
308 * if new label doesn't include it. XXX
309 */
310 if (npp->p_fstype == FS_UNUSED && opp->p_fstype != FS_UNUSED) {
311 npp->p_fstype = opp->p_fstype;
312 npp->p_fsize = opp->p_fsize;
313 npp->p_frag = opp->p_frag;
314 npp->p_cpg = opp->p_cpg;
315 }
316 }
317
318 nlp->d_checksum = 0;
319 nlp->d_checksum = dkcksum(nlp);
320 *olp = *nlp;
321 return (0);
322 }
323
324
325 /*
326 * Write disk label back to device after modification.
327 */
328
329 int
writedisklabel(dev_t dev,void (* strat)(struct buf *),struct disklabel * lp,struct cpu_disklabel * osdep)330 writedisklabel(dev_t dev, void (*strat)(struct buf *),
331 struct disklabel *lp, struct cpu_disklabel *osdep)
332 {
333 struct buf *bp;
334 struct disklabel *dlp;
335 int cyl, netbsdpartoff;
336 int error = 0, rv;
337
338 /* get a buffer and initialize it */
339
340 bp = geteblk((int)lp->d_secsize);
341 bp->b_dev = dev;
342
343 /* do netbsd partitions in the process of getting disklabel? */
344
345 netbsdpartoff = 0;
346 cyl = LABELSECTOR / lp->d_secpercyl;
347
348 if (osdep) {
349 if ((rv = filecore_label_locate(dev, strat,lp, osdep, &cyl,
350 &netbsdpartoff)) != 0 ||
351 (rv = mbr_label_locate(dev, strat, lp, osdep, &cyl,
352 &netbsdpartoff)) != 0) {
353 if (rv > 0)
354 goto done;
355 } else {
356 /*
357 * We didn't find anything we like; NetBSD native.
358 * netbsdpartoff and cyl should be unchanged.
359 */
360 KASSERT(netbsdpartoff == 0);
361 KASSERT(cyl == (LABELSECTOR / lp->d_secpercyl));
362 }
363 }
364
365 /* writelabel: */
366
367 #ifdef DEBUG_LABEL
368 printf("%s: Reading disklabel addr=%08x\n", __func__,
369 netbsdpartoff * DEV_BSIZE);
370 #endif
371
372 /* next, dig out disk label */
373
374 bp->b_blkno = netbsdpartoff + LABELSECTOR;
375 bp->b_cylinder = cyl;
376 bp->b_bcount = lp->d_secsize;
377 bp->b_oflags &= ~(BO_DONE);
378 bp->b_flags |= B_READ;
379 (*strat)(bp);
380
381 /* if successful, locate disk label within block and validate */
382
383 if ((error = biowait(bp)))
384 goto done;
385 for (dlp = (struct disklabel *)bp->b_data;
386 dlp <= (struct disklabel *)((char *)bp->b_data + lp->d_secsize
387 - sizeof(*dlp));
388 dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
389 if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC &&
390 dkcksum(dlp) == 0) {
391 *dlp = *lp;
392 bp->b_flags &= ~(B_READ);
393 bp->b_oflags &= ~(BO_DONE);
394 bp->b_flags |= B_WRITE;
395 (*strat)(bp);
396 error = biowait(bp);
397 goto done;
398 }
399 }
400
401 error = ESRCH;
402
403 done:
404 brelse(bp, 0);
405 return (error);
406 }
407
408 /* End of disksubr.c */
409