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$
39 */
40
41 #include <sys/param.h>
42 #include <sys/buf.h>
43 #include <sys/conf.h>
44 #include <sys/disklabel.h>
45 #define DOSPTYP_EXTENDED 5
46 #define DOSPTYP_EXTENDEDX 15
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,
141 (u_long)dp->dp_size, 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 mbr_offset = DOSBBSECTOR;
178 reread_mbr:
179 /* Read master boot record. */
180 bp = geteblk((int)lp->d_secsize);
181 bp->b_dev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
182 bp->b_blkno = mbr_offset;
183 bp->b_bcount = lp->d_secsize;
184 bp->b_flags |= B_BUSY | B_READ;
185 (*strat)(bp);
186 if (biowait(bp) != 0) {
187 diskerr(bp, dname, "error reading primary partition table",
188 LOG_PRINTF, 0, (struct disklabel *)NULL);
189 printf("\n");
190 error = EIO;
191 goto done;
192 }
193
194 /* Weakly verify it. */
195 cp = bp->b_data;
196 sname = dsname(dname, dkunit(dev), WHOLE_DISK_SLICE, RAW_PART,
197 partname);
198 if (cp[0x1FE] != 0x55 || cp[0x1FF] != 0xAA) {
199 if (bootverbose)
200 printf("%s: invalid primary partition table: no magic\n",
201 sname);
202 error = EINVAL;
203 goto done;
204 }
205 dp0 = (struct dos_partition *)(cp + DOSPARTOFF);
206
207 /* Check for "Ontrack Diskmanager". */
208 for (dospart = 0, dp = dp0; dospart < NDOSPART; dospart++, dp++) {
209 if (dp->dp_typ == DOSPTYP_ONTRACK) {
210 if (bootverbose)
211 printf(
212 "%s: Found \"Ontrack Disk Manager\" on this disk.\n", sname);
213 bp->b_flags |= B_INVAL | B_AGE;
214 brelse(bp);
215 mbr_offset = 63;
216 goto reread_mbr;
217 }
218 }
219
220 if (bcmp(dp0, historical_bogus_partition_table,
221 sizeof historical_bogus_partition_table) == 0) {
222 TRACE(("%s: invalid primary partition table: historical\n",
223 sname));
224 error = EINVAL;
225 goto done;
226 }
227
228 /* Guess the geometry. */
229 /*
230 * TODO:
231 * Perhaps skip entries with 0 size.
232 * Perhaps only look at entries of type DOSPTYP_386BSD.
233 */
234 max_ncyls = 0;
235 max_nsectors = 0;
236 max_ntracks = 0;
237 for (dospart = 0, dp = dp0; dospart < NDOSPART; dospart++, dp++) {
238 int ncyls;
239 int nsectors;
240 int ntracks;
241
242 ncyls = DPCYL(dp->dp_ecyl, dp->dp_esect) + 1;
243 if (max_ncyls < ncyls)
244 max_ncyls = ncyls;
245 nsectors = DPSECT(dp->dp_esect);
246 if (max_nsectors < nsectors)
247 max_nsectors = nsectors;
248 ntracks = dp->dp_ehd + 1;
249 if (max_ntracks < ntracks)
250 max_ntracks = ntracks;
251 }
252
253 /*
254 * Check that we have guessed the geometry right by checking the
255 * partition entries.
256 */
257 /*
258 * TODO:
259 * As above.
260 * Check for overlaps.
261 * Check against d_secperunit if the latter is reliable.
262 */
263 error = 0;
264 for (dospart = 0, dp = dp0; dospart < NDOSPART; dospart++, dp++) {
265 if (dp->dp_scyl == 0 && dp->dp_shd == 0 && dp->dp_ssect == 0
266 && dp->dp_start == 0 && dp->dp_size == 0)
267 continue;
268 sname = dsname(dname, dkunit(dev), BASE_SLICE + dospart,
269 RAW_PART, partname);
270
271 /*
272 * Temporarily ignore errors from this check. We could
273 * simplify things by accepting the table eariler if we
274 * always ignore errors here. Perhaps we should always
275 * accept the table if the magic is right but not let
276 * bad entries affect the geometry.
277 */
278 check_part(sname, dp, mbr_offset, max_nsectors, max_ntracks,
279 mbr_offset);
280 }
281 if (error != 0)
282 goto done;
283
284 /*
285 * Accept the DOS partition table.
286 * First adjust the label (we have been careful not to change it
287 * before we can guarantee success).
288 */
289 secpercyl = (u_long)max_nsectors * max_ntracks;
290 if (secpercyl != 0) {
291 u_long secperunit;
292
293 lp->d_nsectors = max_nsectors;
294 lp->d_ntracks = max_ntracks;
295 lp->d_secpercyl = secpercyl;
296 secperunit = secpercyl * max_ncyls;
297 if (lp->d_secperunit < secperunit)
298 lp->d_secperunit = secperunit;
299 lp->d_ncylinders = lp->d_secperunit / secpercyl;
300 }
301
302 /*
303 * We are passed a pointer to a suitably initialized minimal
304 * slices "struct" with no dangling pointers in it. Replace it
305 * by a maximal one. This usually oversizes the "struct", but
306 * enlarging it while searching for logical drives would be
307 * inconvenient.
308 */
309 free(*sspp, M_DEVBUF);
310 ssp = dsmakeslicestruct(MAX_SLICES, lp);
311 *sspp = ssp;
312
313 /* Initialize normal slices. */
314 sp = &ssp->dss_slices[BASE_SLICE];
315 for (dospart = 0, dp = dp0; dospart < NDOSPART; dospart++, dp++, sp++) {
316 sp->ds_offset = mbr_offset + dp->dp_start;
317 sp->ds_size = dp->dp_size;
318 sp->ds_type = dp->dp_typ;
319 #if 0
320 lp->d_subtype |= (lp->d_subtype & 3) | dospart
321 | DSTYPE_INDOSPART;
322 #endif
323 }
324 ssp->dss_nslices = BASE_SLICE + NDOSPART;
325
326 /* Handle extended partitions. */
327 sp -= NDOSPART;
328 for (dospart = 0; dospart < NDOSPART; dospart++, sp++)
329 if (sp->ds_type == DOSPTYP_EXTENDED ||
330 sp->ds_type == DOSPTYP_EXTENDEDX)
331 extended(dname, bp->b_dev, strat, lp, ssp,
332 sp->ds_offset, sp->ds_size, sp->ds_offset,
333 max_nsectors, max_ntracks, mbr_offset);
334
335 done:
336 bp->b_flags |= B_INVAL | B_AGE;
337 brelse(bp);
338 if (error == EINVAL)
339 error = 0;
340 return (error);
341 }
342
343 void
344 extended(dname, dev, strat, lp, ssp, ext_offset, ext_size, base_ext_offset,
345 nsectors, ntracks, mbr_offset)
346 char *dname;
347 dev_t dev;
348 struct disklabel *lp;
349 d_strategy_t *strat;
350 struct diskslices *ssp;
351 u_long ext_offset;
352 u_long ext_size;
353 u_long base_ext_offset;
354 int nsectors;
355 int ntracks;
356 u_long mbr_offset;
357 {
358 struct buf *bp;
359 u_char *cp;
360 int dospart;
361 struct dos_partition *dp;
362 u_long ext_offsets[NDOSPART];
363 u_long ext_sizes[NDOSPART];
364 char partname[2];
365 int slice;
366 char *sname;
367 struct diskslice *sp;
368
369 /* Read extended boot record. */
370 bp = geteblk((int)lp->d_secsize);
371 bp->b_dev = dev;
372 bp->b_blkno = ext_offset;
373 bp->b_bcount = lp->d_secsize;
374 bp->b_flags |= B_BUSY | B_READ;
375 (*strat)(bp);
376 if (biowait(bp) != 0) {
377 diskerr(bp, dname, "error reading extended partition table",
378 LOG_PRINTF, 0, (struct disklabel *)NULL);
379 printf("\n");
380 goto done;
381 }
382
383 /* Weakly verify it. */
384 cp = bp->b_data;
385 if (cp[0x1FE] != 0x55 || cp[0x1FF] != 0xAA) {
386 sname = dsname(dname, dkunit(dev), WHOLE_DISK_SLICE, RAW_PART,
387 partname);
388 if (bootverbose)
389 printf("%s: invalid extended partition table: no magic\n",
390 sname);
391 goto done;
392 }
393
394 for (dospart = 0,
395 dp = (struct dos_partition *)(bp->b_data + DOSPARTOFF),
396 slice = ssp->dss_nslices, sp = &ssp->dss_slices[slice];
397 dospart < NDOSPART; dospart++, dp++) {
398 ext_sizes[dospart] = 0;
399 if (dp->dp_scyl == 0 && dp->dp_shd == 0 && dp->dp_ssect == 0
400 && dp->dp_start == 0 && dp->dp_size == 0)
401 continue;
402 if (dp->dp_typ == DOSPTYP_EXTENDED ||
403 dp->dp_typ == DOSPTYP_EXTENDEDX) {
404 char buf[32];
405
406 sname = dsname(dname, dkunit(dev), WHOLE_DISK_SLICE,
407 RAW_PART, partname);
408 snprintf(buf, sizeof(buf), "%s", sname);
409 if (strlen(buf) < sizeof buf - 11)
410 strcat(buf, "<extended>");
411 check_part(buf, dp, base_ext_offset, nsectors,
412 ntracks, mbr_offset);
413 ext_offsets[dospart] = base_ext_offset + dp->dp_start;
414 ext_sizes[dospart] = dp->dp_size;
415 } else {
416 sname = dsname(dname, dkunit(dev), slice, RAW_PART,
417 partname);
418 check_part(sname, dp, ext_offset, nsectors, ntracks,
419 mbr_offset);
420 if (slice >= MAX_SLICES) {
421 printf("%s: too many slices\n", sname);
422 slice++;
423 continue;
424 }
425 sp->ds_offset = ext_offset + dp->dp_start;
426 sp->ds_size = dp->dp_size;
427 sp->ds_type = dp->dp_typ;
428 ssp->dss_nslices++;
429 slice++;
430 sp++;
431 }
432 }
433
434 /* If we found any more slices, recursively find all the subslices. */
435 for (dospart = 0; dospart < NDOSPART; dospart++)
436 if (ext_sizes[dospart] != 0)
437 extended(dname, dev, strat, lp, ssp,
438 ext_offsets[dospart], ext_sizes[dospart],
439 base_ext_offset, nsectors, ntracks,
440 mbr_offset);
441
442 done:
443 bp->b_flags |= B_INVAL | B_AGE;
444 brelse(bp);
445 }
Cache object: 1688bfdd32f7565b3dff7b808c43fd6e
|