Remove the priority part of the priority|flags argument to tsleep(). Only
[dragonfly.git] / sys / kern / subr_diskmbr.c
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/kern/subr_diskmbr.c,v 1.45 2000/01/28 10:22:07 bde Exp $
39  * $DragonFly: src/sys/kern/subr_diskmbr.c,v 1.2 2003/06/17 04:28:41 dillon Exp $
40  */
41
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/buf.h>
45 #include <sys/conf.h>
46 #ifdef PC98
47 #define PC98_ATCOMPAT
48 #define dsinit                  atcompat_dsinit
49 #endif
50 #include <sys/disklabel.h>
51 #define DOSPTYP_EXTENDED        5
52 #define DOSPTYP_EXTENDEDX       15
53 #define DOSPTYP_ONTRACK         84
54 #include <sys/diskslice.h>
55 #include <sys/malloc.h>
56 #include <sys/syslog.h>
57
58 #define TRACE(str)      do { if (dsi_debug) printf str; } while (0)
59
60 static volatile u_char dsi_debug;
61
62 static struct dos_partition historical_bogus_partition_table[NDOSPART] = {
63         { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
64         { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
65         { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
66         { 0x80, 0, 1, 0, DOSPTYP_386BSD, 255, 255, 255, 0, 50000, },
67 };
68
69 static int check_part __P((char *sname, struct dos_partition *dp,
70                            u_long offset, int nsectors, int ntracks,
71                            u_long mbr_offset));
72 static void mbr_extended __P((dev_t dev, struct disklabel *lp,
73                               struct diskslices *ssp, u_long ext_offset,
74                               u_long ext_size, u_long base_ext_offset,
75                               int nsectors, int ntracks, u_long mbr_offset,
76                               int level));
77 static int mbr_setslice __P((char *sname, struct disklabel *lp,
78                              struct diskslice *sp, struct dos_partition *dp,
79                              u_long br_offset));
80
81 static int
82 check_part(sname, dp, offset, nsectors, ntracks, mbr_offset )
83         char    *sname;
84         struct dos_partition *dp;
85         u_long  offset;
86         int     nsectors;
87         int     ntracks;
88         u_long  mbr_offset;
89 {
90         int     chs_ecyl;
91         int     chs_esect;
92         int     chs_scyl;
93         int     chs_ssect;
94         int     error;
95         u_long  esector;
96         u_long  esector1;
97         u_long  secpercyl;
98         u_long  ssector;
99         u_long  ssector1;
100
101         secpercyl = (u_long)nsectors * ntracks;
102         chs_scyl = DPCYL(dp->dp_scyl, dp->dp_ssect);
103         chs_ssect = DPSECT(dp->dp_ssect);
104         ssector = chs_ssect - 1 + dp->dp_shd * nsectors + chs_scyl * secpercyl
105                   + mbr_offset;
106         ssector1 = offset + dp->dp_start;
107
108         /*
109          * If ssector1 is on a cylinder >= 1024, then ssector can't be right.
110          * Allow the C/H/S for it to be 1023/ntracks-1/nsectors, or correct
111          * apart from the cylinder being reduced modulo 1024.  Always allow
112          * 1023/255/63.
113          */
114         if ((ssector < ssector1
115              && ((chs_ssect == nsectors && dp->dp_shd == ntracks - 1
116                   && chs_scyl == 1023)
117                  || (secpercyl != 0
118                      && (ssector1 - ssector) % (1024 * secpercyl) == 0)))
119             || (dp->dp_scyl == 255 && dp->dp_shd == 255
120                 && dp->dp_ssect == 255)) {
121                 TRACE(("%s: C/H/S start %d/%d/%d, start %lu: allow\n",
122                        sname, chs_scyl, dp->dp_shd, chs_ssect, ssector1));
123                 ssector = ssector1;
124         }
125
126         chs_ecyl = DPCYL(dp->dp_ecyl, dp->dp_esect);
127         chs_esect = DPSECT(dp->dp_esect);
128         esector = chs_esect - 1 + dp->dp_ehd * nsectors + chs_ecyl * secpercyl
129                   + mbr_offset;
130         esector1 = ssector1 + dp->dp_size - 1;
131
132         /* Allow certain bogus C/H/S values for esector, as above. */
133         if ((esector < esector1
134              && ((chs_esect == nsectors && dp->dp_ehd == ntracks - 1
135                   && chs_ecyl == 1023)
136                  || (secpercyl != 0
137                      && (esector1 - esector) % (1024 * secpercyl) == 0)))
138             || (dp->dp_ecyl == 255 && dp->dp_ehd == 255
139                 && dp->dp_esect == 255)) {
140                 TRACE(("%s: C/H/S end %d/%d/%d, end %lu: allow\n",
141                        sname, chs_ecyl, dp->dp_ehd, chs_esect, esector1));
142                 esector = esector1;
143         }
144
145         error = (ssector == ssector1 && esector == esector1) ? 0 : EINVAL;
146         if (bootverbose)
147                 printf("%s: type 0x%x, start %lu, end = %lu, size %lu %s\n",
148                        sname, dp->dp_typ, ssector1, esector1,
149                        (u_long)dp->dp_size, error ? "" : ": OK");
150         if (ssector != ssector1 && bootverbose)
151                 printf("%s: C/H/S start %d/%d/%d (%lu) != start %lu: invalid\n",
152                        sname, chs_scyl, dp->dp_shd, chs_ssect,
153                        ssector, ssector1);
154         if (esector != esector1 && bootverbose)
155                 printf("%s: C/H/S end %d/%d/%d (%lu) != end %lu: invalid\n",
156                        sname, chs_ecyl, dp->dp_ehd, chs_esect,
157                        esector, esector1);
158         return (error);
159 }
160
161 int
162 dsinit(dev, lp, sspp)
163         dev_t   dev;
164         struct disklabel *lp;
165         struct diskslices **sspp;
166 {
167         struct buf *bp;
168         u_char  *cp;
169         int     dospart;
170         struct dos_partition *dp;
171         struct dos_partition *dp0;
172         struct dos_partition dpcopy[NDOSPART];
173         int     error;
174         int     max_ncyls;
175         int     max_nsectors;
176         int     max_ntracks;
177         u_long  mbr_offset;
178         char    partname[2];
179         u_long  secpercyl;
180         char    *sname;
181         struct diskslice *sp;
182         struct diskslices *ssp;
183
184         mbr_offset = DOSBBSECTOR;
185 reread_mbr:
186         /* Read master boot record. */
187         bp = geteblk((int)lp->d_secsize);
188         bp->b_dev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
189         bp->b_blkno = mbr_offset;
190         bp->b_bcount = lp->d_secsize;
191         bp->b_flags |= B_READ;
192         BUF_STRATEGY(bp, 1);
193         if (biowait(bp) != 0) {
194                 diskerr(bp, "reading primary partition table: error",
195                     LOG_PRINTF, 0, (struct disklabel *)NULL);
196                 printf("\n");
197                 error = EIO;
198                 goto done;
199         }
200
201         /* Weakly verify it. */
202         cp = bp->b_data;
203         sname = dsname(dev, dkunit(dev), WHOLE_DISK_SLICE, RAW_PART, partname);
204         if (cp[0x1FE] != 0x55 || cp[0x1FF] != 0xAA) {
205                 if (bootverbose)
206                         printf("%s: invalid primary partition table: no magic\n",
207                                sname);
208                 error = EINVAL;
209                 goto done;
210         }
211
212         /* Make a copy of the partition table to avoid alignment problems. */
213         memcpy(&dpcopy[0], cp + DOSPARTOFF, sizeof(dpcopy));
214
215         dp0 = &dpcopy[0];
216
217         /* Check for "Ontrack Diskmanager". */
218         for (dospart = 0, dp = dp0; dospart < NDOSPART; dospart++, dp++) {
219                 if (dp->dp_typ == DOSPTYP_ONTRACK) {
220                         if (bootverbose)
221                                 printf(
222             "%s: Found \"Ontrack Disk Manager\" on this disk.\n", sname);
223                         bp->b_flags |= B_INVAL | B_AGE;
224                         brelse(bp);
225                         mbr_offset = 63;
226                         goto reread_mbr;
227                 }
228         }
229
230         if (bcmp(dp0, historical_bogus_partition_table,
231                  sizeof historical_bogus_partition_table) == 0) {
232                 TRACE(("%s: invalid primary partition table: historical\n",
233                        sname));
234                 error = EINVAL;
235                 goto done;
236         }
237
238         /* Guess the geometry. */
239         /*
240          * TODO:
241          * Perhaps skip entries with 0 size.
242          * Perhaps only look at entries of type DOSPTYP_386BSD.
243          */
244         max_ncyls = 0;
245         max_nsectors = 0;
246         max_ntracks = 0;
247         for (dospart = 0, dp = dp0; dospart < NDOSPART; dospart++, dp++) {
248                 int     ncyls;
249                 int     nsectors;
250                 int     ntracks;
251
252                 ncyls = DPCYL(dp->dp_ecyl, dp->dp_esect) + 1;
253                 if (max_ncyls < ncyls)
254                         max_ncyls = ncyls;
255                 nsectors = DPSECT(dp->dp_esect);
256                 if (max_nsectors < nsectors)
257                         max_nsectors = nsectors;
258                 ntracks = dp->dp_ehd + 1;
259                 if (max_ntracks < ntracks)
260                         max_ntracks = ntracks;
261         }
262
263         /*
264          * Check that we have guessed the geometry right by checking the
265          * partition entries.
266          */
267         /*
268          * TODO:
269          * As above.
270          * Check for overlaps.
271          * Check against d_secperunit if the latter is reliable.
272          */
273         error = 0;
274         for (dospart = 0, dp = dp0; dospart < NDOSPART; dospart++, dp++) {
275                 if (dp->dp_scyl == 0 && dp->dp_shd == 0 && dp->dp_ssect == 0
276                     && dp->dp_start == 0 && dp->dp_size == 0)
277                         continue;
278                 sname = dsname(dev, dkunit(dev), BASE_SLICE + dospart,
279                                RAW_PART, partname);
280
281                 /*
282                  * Temporarily ignore errors from this check.  We could
283                  * simplify things by accepting the table eariler if we
284                  * always ignore errors here.  Perhaps we should always
285                  * accept the table if the magic is right but not let
286                  * bad entries affect the geometry.
287                  */
288                 check_part(sname, dp, mbr_offset, max_nsectors, max_ntracks,
289                            mbr_offset);
290         }
291         if (error != 0)
292                 goto done;
293
294         /*
295          * Accept the DOS partition table.
296          * First adjust the label (we have been careful not to change it
297          * before we can guarantee success).
298          */
299         secpercyl = (u_long)max_nsectors * max_ntracks;
300         if (secpercyl != 0) {
301 #if 0
302                 u_long  secperunit;
303 #endif
304
305                 lp->d_nsectors = max_nsectors;
306                 lp->d_ntracks = max_ntracks;
307                 lp->d_secpercyl = secpercyl;
308                 /*
309                  * Temporarily, don't even consider adjusting the drive's
310                  * size, since the adjusted size may exceed the hardware's
311                  * addressing capabilities.  The adjustment helped mainly
312                  * for ancient MFM drives with > 1024 cylinders, but now
313                  * breaks at least IDE drives with 63*16*65536 sectors if
314                  * they are controlled by the wd driver in CHS mode.
315                  */
316 #if 0
317                 secperunit = secpercyl * max_ncyls;
318                 if (lp->d_secperunit < secperunit)
319                         lp->d_secperunit = secperunit;
320 #endif
321                 lp->d_ncylinders = lp->d_secperunit / secpercyl;
322         }
323
324         /*
325          * We are passed a pointer to a suitably initialized minimal
326          * slices "struct" with no dangling pointers in it.  Replace it
327          * by a maximal one.  This usually oversizes the "struct", but
328          * enlarging it while searching for logical drives would be
329          * inconvenient.
330          */
331         free(*sspp, M_DEVBUF);
332         ssp = dsmakeslicestruct(MAX_SLICES, lp);
333         *sspp = ssp;
334
335         /* Initialize normal slices. */
336         sp = &ssp->dss_slices[BASE_SLICE];
337         for (dospart = 0, dp = dp0; dospart < NDOSPART; dospart++, dp++, sp++) {
338                 sname = dsname(dev, dkunit(dev), BASE_SLICE + dospart,
339                                RAW_PART, partname);
340                 (void)mbr_setslice(sname, lp, sp, dp, mbr_offset);
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                     sp->ds_type == DOSPTYP_EXTENDEDX)
349                         mbr_extended(bp->b_dev, lp, ssp,
350                                      sp->ds_offset, sp->ds_size, sp->ds_offset,
351                                      max_nsectors, max_ntracks, mbr_offset, 1);
352
353         /*
354          * mbr_extended() abuses ssp->dss_nslices for the number of slices
355          * that would be found if there were no limit on the number of slices
356          * in *ssp.  Cut it back now.
357          */
358         if (ssp->dss_nslices > MAX_SLICES)
359                 ssp->dss_nslices = MAX_SLICES;
360
361 done:
362         bp->b_flags |= B_INVAL | B_AGE;
363         brelse(bp);
364         if (error == EINVAL)
365                 error = 0;
366         return (error);
367 }
368
369 void
370 mbr_extended(dev, lp, ssp, ext_offset, ext_size, base_ext_offset, nsectors,
371              ntracks, mbr_offset, level)
372         dev_t   dev;
373         struct disklabel *lp;
374         struct diskslices *ssp;
375         u_long  ext_offset;
376         u_long  ext_size;
377         u_long  base_ext_offset;
378         int     nsectors;
379         int     ntracks;
380         u_long  mbr_offset;
381         int     level;
382 {
383         struct buf *bp;
384         u_char  *cp;
385         int     dospart;
386         struct dos_partition *dp;
387         struct dos_partition dpcopy[NDOSPART];
388         u_long  ext_offsets[NDOSPART];
389         u_long  ext_sizes[NDOSPART];
390         char    partname[2];
391         int     slice;
392         char    *sname;
393         struct diskslice *sp;
394
395         if (level >= 16) {
396                 printf(
397         "%s: excessive recursion in search for slices; aborting search\n",
398                        devtoname(dev));
399                 return;
400         }
401
402         /* Read extended boot record. */
403         bp = geteblk((int)lp->d_secsize);
404         bp->b_dev = dev;
405         bp->b_blkno = ext_offset;
406         bp->b_bcount = lp->d_secsize;
407         bp->b_flags |= B_READ;
408         BUF_STRATEGY(bp, 1);
409         if (biowait(bp) != 0) {
410                 diskerr(bp, "reading extended partition table: error",
411                     LOG_PRINTF, 0, (struct disklabel *)NULL);
412                 printf("\n");
413                 goto done;
414         }
415
416         /* Weakly verify it. */
417         cp = bp->b_data;
418         if (cp[0x1FE] != 0x55 || cp[0x1FF] != 0xAA) {
419                 sname = dsname(dev, dkunit(dev), WHOLE_DISK_SLICE, RAW_PART,
420                                partname);
421                 if (bootverbose)
422                         printf("%s: invalid extended partition table: no magic\n",
423                                sname);
424                 goto done;
425         }
426
427         /* Make a copy of the partition table to avoid alignment problems. */
428         memcpy(&dpcopy[0], cp + DOSPARTOFF, sizeof(dpcopy));
429
430         slice = ssp->dss_nslices;
431         for (dospart = 0, dp = &dpcopy[0]; dospart < NDOSPART;
432             dospart++, dp++) {
433                 ext_sizes[dospart] = 0;
434                 if (dp->dp_scyl == 0 && dp->dp_shd == 0 && dp->dp_ssect == 0
435                     && dp->dp_start == 0 && dp->dp_size == 0)
436                         continue;
437                 if (dp->dp_typ == DOSPTYP_EXTENDED ||
438                     dp->dp_typ == DOSPTYP_EXTENDEDX) {
439                         static char buf[32];
440
441                         sname = dsname(dev, dkunit(dev), WHOLE_DISK_SLICE,
442                                        RAW_PART, partname);
443                         snprintf(buf, sizeof(buf), "%s", sname);
444                         if (strlen(buf) < sizeof buf - 11)
445                                 strcat(buf, "<extended>");
446                         check_part(buf, dp, base_ext_offset, nsectors,
447                                    ntracks, mbr_offset);
448                         ext_offsets[dospart] = base_ext_offset + dp->dp_start;
449                         ext_sizes[dospart] = dp->dp_size;
450                 } else {
451                         sname = dsname(dev, dkunit(dev), slice, RAW_PART,
452                                        partname);
453                         check_part(sname, dp, ext_offset, nsectors, ntracks,
454                                    mbr_offset);
455                         if (slice >= MAX_SLICES) {
456                                 printf("%s: too many slices\n", sname);
457                                 slice++;
458                                 continue;
459                         }
460                         sp = &ssp->dss_slices[slice];
461                         if (mbr_setslice(sname, lp, sp, dp, ext_offset) != 0)
462                                 continue;
463                         slice++;
464                 }
465         }
466         ssp->dss_nslices = slice;
467
468         /* If we found any more slices, recursively find all the subslices. */
469         for (dospart = 0; dospart < NDOSPART; dospart++)
470                 if (ext_sizes[dospart] != 0)
471                         mbr_extended(dev, lp, ssp, ext_offsets[dospart],
472                                      ext_sizes[dospart], base_ext_offset,
473                                      nsectors, ntracks, mbr_offset, ++level);
474
475 done:
476         bp->b_flags |= B_INVAL | B_AGE;
477         brelse(bp);
478 }
479
480 static int
481 mbr_setslice(sname, lp, sp, dp, br_offset)
482         char    *sname;
483         struct disklabel *lp;
484         struct diskslice *sp;
485         struct dos_partition *dp;
486         u_long  br_offset;
487 {
488         u_long  offset;
489         u_long  size;
490
491         offset = br_offset + dp->dp_start;
492         if (offset > lp->d_secperunit || offset < br_offset) {
493                 printf(
494                 "%s: slice starts beyond end of the disk: rejecting it\n",
495                        sname);
496                 return (1);
497         }
498         size = lp->d_secperunit - offset;
499         if (size >= dp->dp_size)
500                 size = dp->dp_size;
501         else
502                 printf(
503 "%s: slice extends beyond end of disk: truncating from %lu to %lu sectors\n",
504                        sname, (u_long)dp->dp_size, size);
505         sp->ds_offset = offset;
506         sp->ds_size = size;
507         sp->ds_type = dp->dp_typ;
508 #ifdef PC98_ATCOMPAT
509         /* Fake FreeBSD(98). */
510         if (sp->ds_type == DOSPTYP_386BSD)
511                 sp->ds_type = 0x94;
512 #endif
513 #if 0
514         lp->d_subtype |= (lp->d_subtype & 3) | dospart | DSTYPE_INDOSPART;
515 #endif
516         return (0);
517 }
518
519 #ifdef __alpha__
520 void
521 alpha_fix_srm_checksum(bp)
522         struct buf *bp;
523 {
524         u_int64_t *p;
525         u_int64_t sum;
526         int i;
527
528         p = (u_int64_t *) bp->b_data;
529         sum = 0;
530         for (i = 0; i < 63; i++)
531                 sum += p[i];
532         p[63] = sum;
533 }
534 #endif