1 /* $NetBSD: disksubr.c,v 1.26 2019/04/03 22:10:49 christos 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.26 2019/04/03 22:10:49 christos 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 * Write disk label back to device after modification.
268 */
269
270 int
writedisklabel(dev_t dev,void (* strat)(struct buf *),struct disklabel * lp,struct cpu_disklabel * osdep)271 writedisklabel(dev_t dev, void (*strat)(struct buf *),
272 struct disklabel *lp, struct cpu_disklabel *osdep)
273 {
274 struct buf *bp;
275 struct disklabel *dlp;
276 int cyl, netbsdpartoff;
277 int error = 0, rv;
278
279 /* get a buffer and initialize it */
280
281 bp = geteblk((int)lp->d_secsize);
282 bp->b_dev = dev;
283
284 /* do netbsd partitions in the process of getting disklabel? */
285
286 netbsdpartoff = 0;
287 cyl = LABELSECTOR / lp->d_secpercyl;
288
289 if (osdep) {
290 if ((rv = filecore_label_locate(dev, strat,lp, osdep, &cyl,
291 &netbsdpartoff)) != 0 ||
292 (rv = mbr_label_locate(dev, strat, lp, osdep, &cyl,
293 &netbsdpartoff)) != 0) {
294 if (rv > 0)
295 goto done;
296 } else {
297 /*
298 * We didn't find anything we like; NetBSD native.
299 * netbsdpartoff and cyl should be unchanged.
300 */
301 KASSERT(netbsdpartoff == 0);
302 KASSERT(cyl == (LABELSECTOR / lp->d_secpercyl));
303 }
304 }
305
306 /* writelabel: */
307
308 #ifdef DEBUG_LABEL
309 printf("%s: Reading disklabel addr=%08x\n", __func__,
310 netbsdpartoff * DEV_BSIZE);
311 #endif
312
313 /* next, dig out disk label */
314
315 bp->b_blkno = netbsdpartoff + LABELSECTOR;
316 bp->b_cylinder = cyl;
317 bp->b_bcount = lp->d_secsize;
318 bp->b_oflags &= ~(BO_DONE);
319 bp->b_flags |= B_READ;
320 (*strat)(bp);
321
322 /* if successful, locate disk label within block and validate */
323
324 if ((error = biowait(bp)))
325 goto done;
326 for (dlp = (struct disklabel *)bp->b_data;
327 dlp <= (struct disklabel *)((char *)bp->b_data + lp->d_secsize
328 - sizeof(*dlp));
329 dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
330 if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC &&
331 dkcksum(dlp) == 0) {
332 *dlp = *lp;
333 bp->b_flags &= ~(B_READ);
334 bp->b_oflags &= ~(BO_DONE);
335 bp->b_flags |= B_WRITE;
336 (*strat)(bp);
337 error = biowait(bp);
338 goto done;
339 }
340 }
341
342 error = ESRCH;
343
344 done:
345 brelse(bp, 0);
346 return (error);
347 }
348
349 /* End of disksubr.c */
350