1 /*-
2 * Copyright (c) 1994 Bruce D. Evans.
3 * All rights reserved.
4 *
5 * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * from: @(#)ufs_disksubr.c 7.16 (Berkeley) 5/4/91
37 * from: ufs_disksubr.c,v 1.8 1994/06/07 01:21:39 phk Exp $
38 * $FreeBSD: src/sys/i386/isa/diskslice_machdep.c,v 1.21.2.4 1999/09/05 08:12:32 peter Exp $
39 */
40
41 #include <stddef.h>
42 #include <sys/param.h>
43 #include <sys/buf.h>
44 #include <sys/conf.h>
45 #include <sys/disklabel.h>
46 #define DOSPTYP_EXTENDED 5
47 #define DOSPTYP_ONTRACK 84
48 #include <sys/diskslice.h>
49 #include <sys/malloc.h>
50 #include <sys/syslog.h>
51 #include <sys/systm.h>
52
53 #define TRACE(str) do { if (dsi_debug) printf str; } while (0)
54
55 static volatile u_char dsi_debug;
56
57 static struct dos_partition historical_bogus_partition_table[NDOSPART] = {
58 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
59 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
60 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
61 { 0x80, 0, 1, 0, DOSPTYP_386BSD, 255, 255, 255, 0, 50000, },
62 };
63
64 static int check_part __P((char *sname, struct dos_partition *dp,
65 u_long offset, int nsectors, int ntracks,
66 u_long mbr_offset));
67 static void extended __P((char *dname, dev_t dev, d_strategy_t *strat,
68 struct disklabel *lp, struct diskslices *ssp,
69 u_long ext_offset, u_long ext_size,
70 u_long base_ext_offset, int nsectors, int ntracks,
71 u_long mbr_offset));
72
73 static int
74 check_part(sname, dp, offset, nsectors, ntracks, mbr_offset )
75 char *sname;
76 struct dos_partition *dp;
77 u_long offset;
78 int nsectors;
79 int ntracks;
80 u_long mbr_offset;
81 {
82 int chs_ecyl;
83 int chs_esect;
84 int chs_scyl;
85 int chs_ssect;
86 int error;
87 u_long esector;
88 u_long esector1;
89 u_long secpercyl;
90 u_long ssector;
91 u_long ssector1;
92
93 secpercyl = (u_long)nsectors * ntracks;
94 chs_scyl = DPCYL(dp->dp_scyl, dp->dp_ssect);
95 chs_ssect = DPSECT(dp->dp_ssect);
96 ssector = chs_ssect - 1 + dp->dp_shd * nsectors + chs_scyl * secpercyl
97 + mbr_offset;
98 ssector1 = offset + dp->dp_start;
99
100 /*
101 * If ssector1 is on a cylinder >= 1024, then ssector can't be right.
102 * Allow the C/H/S for it to be 1023/ntracks-1/nsectors, or correct
103 * apart from the cylinder being reduced modulo 1024. Always allow
104 * 1023/255/63.
105 */
106 if (ssector < ssector1
107 && ((chs_ssect == nsectors && dp->dp_shd == ntracks - 1
108 && chs_scyl == 1023)
109 || (secpercyl != 0
110 && (ssector1 - ssector) % (1024 * secpercyl) == 0))
111 || (dp->dp_scyl == 255 && dp->dp_shd == 255
112 && dp->dp_ssect == 255)) {
113 TRACE(("%s: C/H/S start %d/%d/%d, start %lu: allow\n",
114 sname, chs_scyl, dp->dp_shd, chs_ssect, ssector1));
115 ssector = ssector1;
116 }
117
118 chs_ecyl = DPCYL(dp->dp_ecyl, dp->dp_esect);
119 chs_esect = DPSECT(dp->dp_esect);
120 esector = chs_esect - 1 + dp->dp_ehd * nsectors + chs_ecyl * secpercyl
121 + mbr_offset;
122 esector1 = ssector1 + dp->dp_size - 1;
123
124 /* Allow certain bogus C/H/S values for esector, as above. */
125 if (esector < esector1
126 && ((chs_esect == nsectors && dp->dp_ehd == ntracks - 1
127 && chs_ecyl == 1023)
128 || (secpercyl != 0
129 && (esector1 - esector) % (1024 * secpercyl) == 0))
130 || (dp->dp_ecyl == 255 && dp->dp_ehd == 255
131 && dp->dp_esect == 255)) {
132 TRACE(("%s: C/H/S end %d/%d/%d, end %lu: allow\n",
133 sname, chs_ecyl, dp->dp_ehd, chs_esect, esector1));
134 esector = esector1;
135 }
136
137 error = (ssector == ssector1 && esector == esector1) ? 0 : EINVAL;
138 if (bootverbose)
139 printf("%s: type 0x%x, start %lu, end = %lu, size %lu %s\n",
140 sname, dp->dp_typ, ssector1, esector1, dp->dp_size,
141 error ? "" : ": OK");
142 if (ssector != ssector1 && bootverbose)
143 printf("%s: C/H/S start %d/%d/%d (%lu) != start %lu: invalid\n",
144 sname, chs_scyl, dp->dp_shd, chs_ssect,
145 ssector, ssector1);
146 if (esector != esector1 && bootverbose)
147 printf("%s: C/H/S end %d/%d/%d (%lu) != end %lu: invalid\n",
148 sname, chs_ecyl, dp->dp_ehd, chs_esect,
149 esector, esector1);
150 return (error);
151 }
152
153 int
154 dsinit(dname, dev, strat, lp, sspp)
155 char *dname;
156 dev_t dev;
157 d_strategy_t *strat;
158 struct disklabel *lp;
159 struct diskslices **sspp;
160 {
161 struct buf *bp;
162 u_char *cp;
163 int dospart;
164 struct dos_partition *dp;
165 struct dos_partition *dp0;
166 int error;
167 int max_ncyls;
168 int max_nsectors;
169 int max_ntracks;
170 u_long mbr_offset;
171 char partname[2];
172 u_long secpercyl;
173 char *sname;
174 struct diskslice *sp;
175 struct diskslices *ssp;
176
177 /*
178 * Allocate a dummy slices "struct" and initialize it to contain
179 * only an empty compatibility slice (pointing to itself) and a
180 * whole disk slice (covering the disk as described by the label).
181 * If there is an error, then the dummy struct becomes final.
182 */
183 ssp = malloc(offsetof(struct diskslices, dss_slices)
184 + BASE_SLICE * sizeof *sp, M_DEVBUF, M_WAITOK);
185 *sspp = ssp;
186 ssp->dss_first_bsd_slice = COMPATIBILITY_SLICE;
187 ssp->dss_nslices = BASE_SLICE;
188 sp = &ssp->dss_slices[0];
189 bzero(sp, BASE_SLICE * sizeof *sp);
190 sp[WHOLE_DISK_SLICE].ds_size = lp->d_secperunit;
191
192 mbr_offset = DOSBBSECTOR;
193 reread_mbr:
194 /* Read master boot record. */
195 bp = geteblk((int)lp->d_secsize);
196 bp->b_dev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
197 bp->b_blkno = mbr_offset;
198 bp->b_bcount = lp->d_secsize;
199 bp->b_flags |= B_BUSY | B_READ;
200 (*strat)(bp);
201 if (biowait(bp) != 0) {
202 diskerr(bp, dname, "error reading primary partition table",
203 LOG_PRINTF, 0, lp);
204 printf("\n");
205 error = EIO;
206 goto done;
207 }
208
209 /* Weakly verify it. */
210 cp = bp->b_un.b_addr;
211 sname = dsname(dname, dkunit(dev), WHOLE_DISK_SLICE, RAW_PART,
212 partname);
213 if (cp[0x1FE] != 0x55 || cp[0x1FF] != 0xAA) {
214 if (bootverbose)
215 printf("%s: invalid primary partition table: no magic\n",
216 sname);
217 error = EINVAL;
218 goto done;
219 }
220 dp0 = (struct dos_partition *)(cp + DOSPARTOFF);
221
222 /* Check for "Ontrack Diskmanager". */
223 for (dospart = 0, dp = dp0; dospart < NDOSPART; dospart++, dp++) {
224 if (dp->dp_typ == DOSPTYP_ONTRACK) {
225 if (bootverbose)
226 printf(
227 "%s: Found \"Ontrack Disk Manager\" on this disk.\n", sname);
228 bp->b_flags |= B_INVAL | B_AGE;
229 brelse(bp);
230 mbr_offset = 63;
231 goto reread_mbr;
232 }
233 }
234
235 if (bcmp(dp0, historical_bogus_partition_table,
236 sizeof historical_bogus_partition_table) == 0) {
237 TRACE(("%s: invalid primary partition table: historical\n",
238 sname));
239 error = EINVAL;
240 goto done;
241 }
242
243 /* Guess the geometry. */
244 /*
245 * TODO:
246 * Perhaps skip entries with 0 size.
247 * Perhaps only look at entries of type DOSPTYP_386BSD.
248 */
249 max_ncyls = 0;
250 max_nsectors = 0;
251 max_ntracks = 0;
252 for (dospart = 0, dp = dp0; dospart < NDOSPART; dospart++, dp++) {
253 int ncyls;
254 int nsectors;
255 int ntracks;
256
257 ncyls = DPCYL(dp->dp_ecyl, dp->dp_esect) + 1;
258 if (max_ncyls < ncyls)
259 max_ncyls = ncyls;
260 nsectors = DPSECT(dp->dp_esect);
261 if (max_nsectors < nsectors)
262 max_nsectors = nsectors;
263 ntracks = dp->dp_ehd + 1;
264 if (max_ntracks < ntracks)
265 max_ntracks = ntracks;
266 }
267
268 /*
269 * Check that we have guessed the geometry right by checking the
270 * partition entries.
271 */
272 /*
273 * TODO:
274 * As above.
275 * Check for overlaps.
276 * Check against d_secperunit if the latter is reliable.
277 */
278 error = 0;
279 for (dospart = 0, dp = dp0; dospart < NDOSPART; dospart++, dp++) {
280 if (dp->dp_scyl == 0 && dp->dp_shd == 0 && dp->dp_ssect == 0
281 && dp->dp_start == 0 && dp->dp_size == 0)
282 continue;
283 sname = dsname(dname, dkunit(dev), BASE_SLICE + dospart,
284 RAW_PART, partname);
285
286 /*
287 * Temporarily ignore errors from this check. We could
288 * simplify things by accepting the table eariler if we
289 * always ignore errors here. Perhaps we should always
290 * accept the table if the magic is right but not let
291 * bad entries affect the geometry.
292 */
293 check_part(sname, dp, mbr_offset, max_nsectors, max_ntracks,
294 mbr_offset);
295 }
296 if (error != 0)
297 goto done;
298
299 /*
300 * Accept the DOS partition table.
301 * First adjust the label (we have been careful not to change it
302 * before we can guarantee success).
303 */
304 secpercyl = (u_long)max_nsectors * max_ntracks;
305 if (secpercyl != 0) {
306 u_long secperunit;
307
308 lp->d_nsectors = max_nsectors;
309 lp->d_ntracks = max_ntracks;
310 lp->d_secpercyl = secpercyl;
311 secperunit = secpercyl * max_ncyls;
312 if (lp->d_secperunit < secperunit)
313 lp->d_secperunit = secperunit;
314 lp->d_ncylinders = lp->d_secperunit / secpercyl;
315 }
316
317 /*
318 * Free the dummy slices "struct" and allocate a real new one.
319 * Initialize special slices as above.
320 */
321 free(ssp, M_DEVBUF);
322 ssp = malloc(offsetof(struct diskslices, dss_slices)
323 #define MAX_SLICES_SUPPORTED MAX_SLICES /* was (BASE_SLICE + NDOSPART) */
324 + MAX_SLICES_SUPPORTED * sizeof *sp, M_DEVBUF, M_WAITOK);
325 *sspp = ssp;
326 ssp->dss_first_bsd_slice = COMPATIBILITY_SLICE;
327 sp = &ssp->dss_slices[0];
328 bzero(sp, MAX_SLICES_SUPPORTED * sizeof *sp);
329 sp[WHOLE_DISK_SLICE].ds_size = lp->d_secperunit;
330
331 /* Initialize normal slices. */
332 sp += BASE_SLICE;
333 for (dospart = 0, dp = dp0; dospart < NDOSPART; dospart++, dp++, sp++) {
334 sp->ds_offset = mbr_offset + dp->dp_start;
335 sp->ds_size = dp->dp_size;
336 sp->ds_type = dp->dp_typ;
337 #if 0
338 lp->d_subtype |= (lp->d_subtype & 3) | dospart
339 | DSTYPE_INDOSPART;
340 #endif
341 }
342 ssp->dss_nslices = BASE_SLICE + NDOSPART;
343
344 /* Handle extended partitions. */
345 sp -= NDOSPART;
346 for (dospart = 0; dospart < NDOSPART; dospart++, sp++)
347 if (sp->ds_type == DOSPTYP_EXTENDED)
348 extended(dname, bp->b_dev, strat, lp, ssp,
349 sp->ds_offset, sp->ds_size, sp->ds_offset,
350 max_nsectors, max_ntracks, mbr_offset);
351
352 done:
353 bp->b_flags |= B_INVAL | B_AGE;
354 brelse(bp);
355 if (error == EINVAL)
356 error = 0;
357 return (error);
358 }
359
360 void
361 extended(dname, dev, strat, lp, ssp, ext_offset, ext_size, base_ext_offset,
362 nsectors, ntracks, mbr_offset)
363 char *dname;
364 dev_t dev;
365 struct disklabel *lp;
366 d_strategy_t *strat;
367 struct diskslices *ssp;
368 u_long ext_offset;
369 u_long ext_size;
370 u_long base_ext_offset;
371 int nsectors;
372 int ntracks;
373 u_long mbr_offset;
374 {
375 struct buf *bp;
376 u_char *cp;
377 int dospart;
378 struct dos_partition *dp;
379 u_long ext_offsets[NDOSPART];
380 u_long ext_sizes[NDOSPART];
381 char partname[2];
382 int slice;
383 char *sname;
384 struct diskslice *sp;
385
386 /* Read extended boot record. */
387 bp = geteblk((int)lp->d_secsize);
388 bp->b_dev = dev;
389 bp->b_blkno = ext_offset;
390 bp->b_bcount = lp->d_secsize;
391 bp->b_flags |= B_BUSY | B_READ;
392 (*strat)(bp);
393 if (biowait(bp) != 0) {
394 diskerr(bp, dname, "error reading extended partition table",
395 LOG_PRINTF, 0, lp);
396 printf("\n");
397 goto done;
398 }
399
400 /* Weakly verify it. */
401 cp = bp->b_un.b_addr;
402 if (cp[0x1FE] != 0x55 || cp[0x1FF] != 0xAA) {
403 sname = dsname(dname, dkunit(dev), WHOLE_DISK_SLICE, RAW_PART,
404 partname);
405 if (bootverbose)
406 printf("%s: invalid extended partition table: no magic\n",
407 sname);
408 goto done;
409 }
410
411 for (dospart = 0,
412 dp = (struct dos_partition *)(bp->b_un.b_addr + DOSPARTOFF),
413 slice = ssp->dss_nslices, sp = &ssp->dss_slices[slice];
414 dospart < NDOSPART; dospart++, dp++) {
415 ext_sizes[dospart] = 0;
416 if (dp->dp_scyl == 0 && dp->dp_shd == 0 && dp->dp_ssect == 0
417 && dp->dp_start == 0 && dp->dp_size == 0)
418 continue;
419 if (dp->dp_typ == DOSPTYP_EXTENDED) {
420 char buf[32];
421
422 sname = dsname(dname, dkunit(dev), WHOLE_DISK_SLICE,
423 RAW_PART, partname);
424 strcpy(buf, sname);
425 if (strlen(buf) < sizeof buf - 11)
426 strcat(buf, "<extended>");
427 check_part(buf, dp, base_ext_offset, nsectors,
428 ntracks, mbr_offset);
429 ext_offsets[dospart] = base_ext_offset + dp->dp_start;
430 ext_sizes[dospart] = dp->dp_size;
431 } else {
432 sname = dsname(dname, dkunit(dev), slice, RAW_PART,
433 partname);
434 check_part(sname, dp, ext_offset, nsectors, ntracks,
435 mbr_offset);
436 if (slice >= MAX_SLICES) {
437 printf("%s: too many slices\n", sname);
438 slice++;
439 continue;
440 }
441 sp->ds_offset = ext_offset + dp->dp_start;
442 sp->ds_size = dp->dp_size;
443 sp->ds_type = dp->dp_typ;
444 ssp->dss_nslices++;
445 slice++;
446 sp++;
447 }
448 }
449
450 /* If we found any more slices, recursively find all the subslices. */
451 for (dospart = 0; dospart < NDOSPART; dospart++)
452 if (ext_sizes[dospart] != 0)
453 extended(dname, dev, strat, lp, ssp,
454 ext_offsets[dospart], ext_sizes[dospart],
455 base_ext_offset, nsectors, ntracks,
456 mbr_offset);
457
458 done:
459 bp->b_flags |= B_INVAL | B_AGE;
460 brelse(bp);
461 }
Cache object: 7833f5a9d6d4ea3a249f56bd9e54a9a9
|