]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - stand/i386/libi386/biosdisk.c
MFV 364468:
[FreeBSD/FreeBSD.git] / stand / i386 / libi386 / biosdisk.c
1 /*-
2  * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3  * Copyright (c) 2012 Andrey V. Elsukov <ae@FreeBSD.org>
4  * 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  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30
31 /*
32  * BIOS disk device handling.
33  *
34  * Ideas and algorithms from:
35  *
36  * - NetBSD libi386/biosdisk.c
37  * - FreeBSD biosboot/disk.c
38  *
39  */
40
41 #include <sys/disk.h>
42 #include <sys/limits.h>
43 #include <sys/queue.h>
44 #include <stand.h>
45 #include <machine/bootinfo.h>
46 #include <stdarg.h>
47 #include <stdbool.h>
48
49 #include <bootstrap.h>
50 #include <btxv86.h>
51 #include <edd.h>
52 #include "disk.h"
53 #include "libi386.h"
54
55 #define BIOS_NUMDRIVES          0x475
56 #define BIOSDISK_SECSIZE        512
57 #define BUFSIZE                 (1 * BIOSDISK_SECSIZE)
58
59 #define DT_ATAPI        0x10    /* disk type for ATAPI floppies */
60 #define WDMAJOR         0       /* major numbers for devices we frontend for */
61 #define WFDMAJOR        1
62 #define FDMAJOR         2
63 #define DAMAJOR         4
64 #define ACDMAJOR        117
65 #define CDMAJOR         15
66
67 /*
68  * INT13 commands
69  */
70 #define CMD_RESET       0x0000
71 #define CMD_READ_CHS    0x0200
72 #define CMD_WRITE_CHS   0x0300
73 #define CMD_READ_PARAM  0x0800
74 #define CMD_DRIVE_TYPE  0x1500
75 #define CMD_CHECK_EDD   0x4100
76 #define CMD_READ_LBA    0x4200
77 #define CMD_WRITE_LBA   0x4300
78 #define CMD_EXT_PARAM   0x4800
79 #define CMD_CD_GET_STATUS 0x4b01
80
81 #define DISK_BIOS       0x13
82
83 #ifdef DISK_DEBUG
84 #define DPRINTF(fmt, args...)   printf("%s: " fmt "\n", __func__, ## args)
85 #else
86 #define DPRINTF(fmt, args...)   ((void)0)
87 #endif
88
89 struct specification_packet {
90         uint8_t         sp_size;
91         uint8_t         sp_bootmedia;
92         uint8_t         sp_drive;
93         uint8_t         sp_controller;
94         uint32_t        sp_lba;
95         uint16_t        sp_devicespec;
96         uint16_t        sp_buffersegment;
97         uint16_t        sp_loadsegment;
98         uint16_t        sp_sectorcount;
99         uint16_t        sp_cylsec;
100         uint8_t         sp_head;
101         uint8_t         sp_dummy[16];   /* Avoid memory corruption */
102 };
103
104 /*
105  * List of BIOS devices, translation from disk unit number to
106  * BIOS unit number.
107  */
108 typedef struct bdinfo
109 {
110         STAILQ_ENTRY(bdinfo)    bd_link;        /* link in device list */
111         int             bd_unit;        /* BIOS unit number */
112         int             bd_cyl;         /* BIOS geometry */
113         int             bd_hds;
114         int             bd_sec;
115         int             bd_flags;
116 #define BD_MODEINT13    0x0000
117 #define BD_MODEEDD1     0x0001
118 #define BD_MODEEDD3     0x0002
119 #define BD_MODEEDD      (BD_MODEEDD1 | BD_MODEEDD3)
120 #define BD_MODEMASK     0x0003
121 #define BD_FLOPPY       0x0004
122 #define BD_CDROM        0x0008
123 #define BD_NO_MEDIA     0x0010
124         int             bd_type;        /* BIOS 'drive type' (floppy only) */
125         uint16_t        bd_sectorsize;  /* Sector size */
126         uint64_t        bd_sectors;     /* Disk size */
127         int             bd_open;        /* reference counter */
128         void            *bd_bcache;     /* buffer cache data */
129 } bdinfo_t;
130
131 #define BD_RD           0
132 #define BD_WR           1
133
134 typedef STAILQ_HEAD(bdinfo_list, bdinfo) bdinfo_list_t;
135 static bdinfo_list_t fdinfo = STAILQ_HEAD_INITIALIZER(fdinfo);
136 static bdinfo_list_t cdinfo = STAILQ_HEAD_INITIALIZER(cdinfo);
137 static bdinfo_list_t hdinfo = STAILQ_HEAD_INITIALIZER(hdinfo);
138
139 static void bd_io_workaround(bdinfo_t *);
140 static int bd_io(struct disk_devdesc *, bdinfo_t *, daddr_t, int, caddr_t, int);
141 static bool bd_int13probe(bdinfo_t *);
142
143 static int bd_init(void);
144 static int cd_init(void);
145 static int fd_init(void);
146 static int bd_strategy(void *devdata, int flag, daddr_t dblk, size_t size,
147     char *buf, size_t *rsize);
148 static int bd_realstrategy(void *devdata, int flag, daddr_t dblk, size_t size,
149     char *buf, size_t *rsize);
150 static int bd_open(struct open_file *f, ...);
151 static int bd_close(struct open_file *f);
152 static int bd_ioctl(struct open_file *f, u_long cmd, void *data);
153 static int bd_print(int verbose);
154 static int cd_print(int verbose);
155 static int fd_print(int verbose);
156 static void bd_reset_disk(int);
157 static int bd_get_diskinfo_std(struct bdinfo *);
158
159 struct devsw biosfd = {
160         .dv_name = "fd",
161         .dv_type = DEVT_FD,
162         .dv_init = fd_init,
163         .dv_strategy = bd_strategy,
164         .dv_open = bd_open,
165         .dv_close = bd_close,
166         .dv_ioctl = bd_ioctl,
167         .dv_print = fd_print,
168         .dv_cleanup = NULL
169 };
170
171 struct devsw bioscd = {
172         .dv_name = "cd",
173         .dv_type = DEVT_CD,
174         .dv_init = cd_init,
175         .dv_strategy = bd_strategy,
176         .dv_open = bd_open,
177         .dv_close = bd_close,
178         .dv_ioctl = bd_ioctl,
179         .dv_print = cd_print,
180         .dv_cleanup = NULL
181 };
182
183 struct devsw bioshd = {
184         .dv_name = "disk",
185         .dv_type = DEVT_DISK,
186         .dv_init = bd_init,
187         .dv_strategy = bd_strategy,
188         .dv_open = bd_open,
189         .dv_close = bd_close,
190         .dv_ioctl = bd_ioctl,
191         .dv_print = bd_print,
192         .dv_cleanup = NULL
193 };
194
195 static bdinfo_list_t *
196 bd_get_bdinfo_list(struct devsw *dev)
197 {
198         if (dev->dv_type == DEVT_DISK)
199                 return (&hdinfo);
200         if (dev->dv_type == DEVT_CD)
201                 return (&cdinfo);
202         if (dev->dv_type == DEVT_FD)
203                 return (&fdinfo);
204         return (NULL);
205 }
206
207 /* XXX this gets called way way too often, investigate */
208 static bdinfo_t *
209 bd_get_bdinfo(struct devdesc *dev)
210 {
211         bdinfo_list_t *bdi;
212         bdinfo_t *bd = NULL;
213         int unit;
214
215         bdi = bd_get_bdinfo_list(dev->d_dev);
216         if (bdi == NULL)
217                 return (bd);
218
219         unit = 0;
220         STAILQ_FOREACH(bd, bdi, bd_link) {
221                 if (unit == dev->d_unit)
222                         return (bd);
223                 unit++;
224         }
225         return (bd);
226 }
227
228 /*
229  * Translate between BIOS device numbers and our private unit numbers.
230  */
231 int
232 bd_bios2unit(int biosdev)
233 {
234         bdinfo_list_t *bdi[] = { &fdinfo, &cdinfo, &hdinfo, NULL };
235         bdinfo_t *bd;
236         int i, unit;
237
238         DPRINTF("looking for bios device 0x%x", biosdev);
239         for (i = 0; bdi[i] != NULL; i++) {
240                 unit = 0;
241                 STAILQ_FOREACH(bd, bdi[i], bd_link) {
242                         if (bd->bd_unit == biosdev) {
243                                 DPRINTF("bd unit %d is BIOS device 0x%x", unit,
244                                     bd->bd_unit);
245                                 return (unit);
246                         }
247                         unit++;
248                 }
249         }
250         return (-1);
251 }
252
253 int
254 bd_unit2bios(struct i386_devdesc *dev)
255 {
256         bdinfo_list_t *bdi;
257         bdinfo_t *bd;
258         int unit;
259
260         bdi = bd_get_bdinfo_list(dev->dd.d_dev);
261         if (bdi == NULL)
262                 return (-1);
263
264         unit = 0;
265         STAILQ_FOREACH(bd, bdi, bd_link) {
266                 if (unit == dev->dd.d_unit)
267                         return (bd->bd_unit);
268                 unit++;
269         }
270         return (-1);
271 }
272
273 /*
274  * Use INT13 AH=15 - Read Drive Type.
275  */
276 static int
277 fd_count(void)
278 {
279         int drive;
280
281         for (drive = 0; drive < MAXBDDEV; drive++) {
282                 bd_reset_disk(drive);
283
284                 v86.ctl = V86_FLAGS;
285                 v86.addr = DISK_BIOS;
286                 v86.eax = CMD_DRIVE_TYPE;
287                 v86.edx = drive;
288                 v86int();
289
290                 if (V86_CY(v86.efl))
291                         break;
292
293                 if ((v86.eax & 0x300) == 0)
294                         break;
295         }
296
297         return (drive);
298 }
299
300 /*
301  * Quiz the BIOS for disk devices, save a little info about them.
302  */
303 static int
304 fd_init(void)
305 {
306         int unit, numfd;
307         bdinfo_t *bd;
308
309         numfd = fd_count();
310         for (unit = 0; unit < numfd; unit++) {
311                 if ((bd = calloc(1, sizeof(*bd))) == NULL)
312                         break;
313
314                 bd->bd_sectorsize = BIOSDISK_SECSIZE;
315                 bd->bd_flags = BD_FLOPPY;
316                 bd->bd_unit = unit;
317
318                 /* Use std diskinfo for floppy drive */
319                 if (bd_get_diskinfo_std(bd) != 0) {
320                         free(bd);
321                         break;
322                 }
323                 if (bd->bd_sectors == 0)
324                         bd->bd_flags |= BD_NO_MEDIA;
325
326                 printf("BIOS drive %c: is %s%d\n", ('A' + unit),
327                     biosfd.dv_name, unit);
328
329                 STAILQ_INSERT_TAIL(&fdinfo, bd, bd_link);
330         }
331
332         bcache_add_dev(unit);
333         return (0);
334 }
335
336 static int
337 bd_init(void)
338 {
339         int base, unit;
340         bdinfo_t *bd;
341
342         base = 0x80;
343         for (unit = 0; unit < *(unsigned char *)PTOV(BIOS_NUMDRIVES); unit++) {
344                 /*
345                  * Check the BIOS equipment list for number of fixed disks.
346                  */
347                 if ((bd = calloc(1, sizeof(*bd))) == NULL)
348                         break;
349                 bd->bd_unit = base + unit;
350                 if (!bd_int13probe(bd)) {
351                         free(bd);
352                         break;
353                 }
354
355                 printf("BIOS drive %c: is %s%d\n", ('C' + unit),
356                     bioshd.dv_name, unit);
357
358                 STAILQ_INSERT_TAIL(&hdinfo, bd, bd_link);
359         }
360         bcache_add_dev(unit);
361         return (0);
362 }
363
364 /*
365  * We can't quiz, we have to be told what device to use, so this function
366  * doesn't do anything.  Instead, the loader calls bc_add() with the BIOS
367  * device number to add.
368  */
369 static int
370 cd_init(void)
371 {
372
373         return (0);
374 }
375
376 /*
377  * Information from bootable CD-ROM.
378  */
379 static int
380 bd_get_diskinfo_cd(struct bdinfo *bd)
381 {
382         struct specification_packet bc_sp;
383         int ret = -1;
384
385         (void) memset(&bc_sp, 0, sizeof (bc_sp));
386         /* Set sp_size as per specification. */
387         bc_sp.sp_size = sizeof (bc_sp) - sizeof (bc_sp.sp_dummy);
388
389         v86.ctl = V86_FLAGS;
390         v86.addr = DISK_BIOS;
391         v86.eax = CMD_CD_GET_STATUS;
392         v86.edx = bd->bd_unit;
393         v86.ds = VTOPSEG(&bc_sp);
394         v86.esi = VTOPOFF(&bc_sp);
395         v86int();
396
397         if ((v86.eax & 0xff00) == 0 &&
398             bc_sp.sp_drive == bd->bd_unit) {
399                 bd->bd_cyl = ((bc_sp.sp_cylsec & 0xc0) << 2) +
400                     ((bc_sp.sp_cylsec & 0xff00) >> 8) + 1;
401                 bd->bd_sec = bc_sp.sp_cylsec & 0x3f;
402                 bd->bd_hds = bc_sp.sp_head + 1;
403                 bd->bd_sectors = (uint64_t)bd->bd_cyl * bd->bd_hds * bd->bd_sec;
404
405                 if (bc_sp.sp_bootmedia & 0x0F) {
406                         /* Floppy or hard-disk emulation */
407                         bd->bd_sectorsize = BIOSDISK_SECSIZE;
408                         return (-1);
409                 } else {
410                         bd->bd_sectorsize = 2048;
411                         bd->bd_flags = BD_MODEEDD | BD_CDROM;
412                         ret = 0;
413                 }
414         }
415
416         /*
417          * If this is the boot_drive, default to non-emulation bootable CD-ROM.
418          */
419         if (ret != 0 && bd->bd_unit >= 0x88) {
420                 bd->bd_cyl = 0;
421                 bd->bd_hds = 1;
422                 bd->bd_sec = 15;
423                 bd->bd_sectorsize = 2048;
424                 bd->bd_flags = BD_MODEEDD | BD_CDROM;
425                 bd->bd_sectors = 0;
426                 ret = 0;
427         }
428
429         /*
430          * Note we can not use bd_get_diskinfo_ext() nor bd_get_diskinfo_std()
431          * here - some systems do get hung with those.
432          */
433         /*
434          * Still no size? use 7.961GB. The size does not really matter
435          * as long as it is reasonably large to make our reads to pass
436          * the sector count check.
437          */
438         if (bd->bd_sectors == 0)
439                 bd->bd_sectors = 4173824;
440  
441         return (ret);
442 }
443
444 int
445 bc_add(int biosdev)
446 {
447         bdinfo_t *bd;
448         int nbcinfo = 0;
449
450         if (!STAILQ_EMPTY(&cdinfo))
451                 return (-1);
452
453         if ((bd = calloc(1, sizeof(*bd))) == NULL)
454                 return (-1);
455
456         bd->bd_unit = biosdev;
457         if (bd_get_diskinfo_cd(bd) < 0) {
458                 free(bd);
459                 return (-1);
460         }
461
462         STAILQ_INSERT_TAIL(&cdinfo, bd, bd_link);
463         printf("BIOS CD is cd%d\n", nbcinfo);
464         nbcinfo++;
465         bcache_add_dev(nbcinfo);        /* register cd device in bcache */
466         return(0);
467 }
468
469 /*
470  * Return EDD version or 0 if EDD is not supported on this drive.
471  */
472 static int
473 bd_check_extensions(int unit)
474 {
475         /* do not use ext calls for floppy devices */
476         if (unit < 0x80)
477                 return (0);
478
479         /* Determine if we can use EDD with this device. */
480         v86.ctl = V86_FLAGS;
481         v86.addr = DISK_BIOS;
482         v86.eax = CMD_CHECK_EDD;
483         v86.edx = unit;
484         v86.ebx = EDD_QUERY_MAGIC;
485         v86int();
486
487         if (V86_CY(v86.efl) ||                  /* carry set */
488             (v86.ebx & 0xffff) != EDD_INSTALLED) /* signature */
489                 return (0);
490
491         /* extended disk access functions (AH=42h-44h,47h,48h) supported */
492         if ((v86.ecx & EDD_INTERFACE_FIXED_DISK) == 0)
493                 return (0);
494
495         return ((v86.eax >> 8) & 0xff);
496 }
497
498 static void
499 bd_reset_disk(int unit)
500 {
501         /* reset disk */
502         v86.ctl = V86_FLAGS;
503         v86.addr = DISK_BIOS;
504         v86.eax = CMD_RESET;
505         v86.edx = unit;
506         v86int();
507 }
508
509 /*
510  * Read CHS info. Return 0 on success, error otherwise.
511  */
512 static int
513 bd_get_diskinfo_std(struct bdinfo *bd)
514 {
515         bzero(&v86, sizeof(v86));
516         v86.ctl = V86_FLAGS;
517         v86.addr = DISK_BIOS;
518         v86.eax = CMD_READ_PARAM;
519         v86.edx = bd->bd_unit;
520         v86int();
521
522         if (V86_CY(v86.efl) && ((v86.eax & 0xff00) != 0))
523                 return ((v86.eax & 0xff00) >> 8);
524
525         /* return custom error on absurd sector number */
526         if ((v86.ecx & 0x3f) == 0)
527                 return (0x60);
528
529         bd->bd_cyl = ((v86.ecx & 0xc0) << 2) + ((v86.ecx & 0xff00) >> 8) + 1;
530         /* Convert max head # -> # of heads */
531         bd->bd_hds = ((v86.edx & 0xff00) >> 8) + 1;
532         bd->bd_sec = v86.ecx & 0x3f;
533         bd->bd_type = v86.ebx;
534         bd->bd_sectors = (uint64_t)bd->bd_cyl * bd->bd_hds * bd->bd_sec;
535
536         return (0);
537 }
538
539 /*
540  * Read EDD info. Return 0 on success, error otherwise.
541  *
542  * Avoid stack corruption on some systems by adding extra bytes to
543  * params block.
544  */
545 static int
546 bd_get_diskinfo_ext(struct bdinfo *bd)
547 {
548         struct disk_params {
549                 struct edd_params head;
550                 struct edd_device_path_v3 device_path;
551                 uint8_t dummy[16];
552         } __packed dparams;
553         struct edd_params *params;
554         uint64_t total;
555
556         params = &dparams.head;
557
558         /* Get disk params */
559         bzero(&dparams, sizeof(dparams));
560         params->len = sizeof(struct edd_params_v3);
561         v86.ctl = V86_FLAGS;
562         v86.addr = DISK_BIOS;
563         v86.eax = CMD_EXT_PARAM;
564         v86.edx = bd->bd_unit;
565         v86.ds = VTOPSEG(&dparams);
566         v86.esi = VTOPOFF(&dparams);
567         v86int();
568
569         if (V86_CY(v86.efl) && ((v86.eax & 0xff00) != 0))
570                 return ((v86.eax & 0xff00) >> 8);
571
572         /*
573          * Sector size must be a multiple of 512 bytes.
574          * An alternate test would be to check power of 2,
575          * powerof2(params.sector_size).
576          * 16K is largest read buffer we can use at this time.
577          */
578         if (params->sector_size >= 512 &&
579             params->sector_size <= 16384 &&
580             (params->sector_size % BIOSDISK_SECSIZE) == 0)
581                 bd->bd_sectorsize = params->sector_size;
582
583         bd->bd_cyl = params->cylinders;
584         bd->bd_hds = params->heads;
585         bd->bd_sec = params->sectors_per_track;
586
587         if (params->sectors != 0) {
588                 total = params->sectors;
589         } else {
590                 total = (uint64_t)params->cylinders *
591                     params->heads * params->sectors_per_track;
592         }
593         bd->bd_sectors = total;
594
595         return (0);
596 }
597
598 /*
599  * Try to detect a device supported by the legacy int13 BIOS
600  */
601 static bool
602 bd_int13probe(bdinfo_t *bd)
603 {
604         int edd, ret;
605
606         bd->bd_flags &= ~BD_NO_MEDIA;
607
608         if ((bd->bd_flags & BD_CDROM) != 0) {
609                 return (bd_get_diskinfo_cd(bd) == 0);
610         }
611
612         edd = bd_check_extensions(bd->bd_unit);
613         if (edd == 0)
614                 bd->bd_flags |= BD_MODEINT13;
615         else if (edd < 0x30)
616                 bd->bd_flags |= BD_MODEEDD1;
617         else
618                 bd->bd_flags |= BD_MODEEDD3;
619
620         /* Default sector size */
621         if (bd->bd_sectorsize == 0)
622                 bd->bd_sectorsize = BIOSDISK_SECSIZE;
623
624         /*
625          * Test if the floppy device is present, so we can avoid receiving
626          * bogus information from bd_get_diskinfo_std().
627          */
628         if (bd->bd_unit < 0x80) {
629                 /* reset disk */
630                 bd_reset_disk(bd->bd_unit);
631
632                 /* Get disk type */
633                 v86.ctl = V86_FLAGS;
634                 v86.addr = DISK_BIOS;
635                 v86.eax = CMD_DRIVE_TYPE;
636                 v86.edx = bd->bd_unit;
637                 v86int();
638                 if (V86_CY(v86.efl) || (v86.eax & 0x300) == 0)
639                         return (false);
640         }
641
642         ret = 1;
643         if (edd != 0)
644                 ret = bd_get_diskinfo_ext(bd);
645         if (ret != 0 || bd->bd_sectors == 0)
646                 ret = bd_get_diskinfo_std(bd);
647
648         if (ret != 0 && bd->bd_unit < 0x80) {
649                 /* Set defaults for 1.44 floppy */
650                 bd->bd_cyl = 80;
651                 bd->bd_hds = 2;
652                 bd->bd_sec = 18;
653                 bd->bd_sectors = 2880;
654                 /* Since we are there, there most likely is no media */
655                 bd->bd_flags |= BD_NO_MEDIA;
656                 ret = 0;
657         }
658
659         if (ret != 0) {
660                 if (bd->bd_sectors != 0 && edd != 0) {
661                         bd->bd_sec = 63;
662                         bd->bd_hds = 255;
663                         bd->bd_cyl =
664                             (bd->bd_sectors + bd->bd_sec * bd->bd_hds - 1) /
665                             bd->bd_sec * bd->bd_hds;
666                 } else {
667                         const char *dv_name;
668
669                         if ((bd->bd_flags & BD_FLOPPY) != 0)
670                                 dv_name = biosfd.dv_name;
671                         else
672                                 dv_name = bioshd.dv_name;
673
674                         printf("Can not get information about %s unit %#x\n",
675                             dv_name, bd->bd_unit);
676                         return (false);
677                 }
678         }
679
680         if (bd->bd_sec == 0)
681                 bd->bd_sec = 63;
682         if (bd->bd_hds == 0)
683                 bd->bd_hds = 255;
684
685         if (bd->bd_sectors == 0)
686                 bd->bd_sectors = (uint64_t)bd->bd_cyl * bd->bd_hds * bd->bd_sec;
687
688         DPRINTF("unit 0x%x geometry %d/%d/%d\n", bd->bd_unit, bd->bd_cyl,
689             bd->bd_hds, bd->bd_sec);
690
691         return (true);
692 }
693
694 static int
695 bd_count(bdinfo_list_t *bdi)
696 {
697         bdinfo_t *bd;
698         int i;
699
700         i = 0;
701         STAILQ_FOREACH(bd, bdi, bd_link)
702                 i++;
703         return (i);
704 }
705
706 /*
707  * Print information about disks
708  */
709 static int
710 bd_print_common(struct devsw *dev, bdinfo_list_t *bdi, int verbose)
711 {
712         char line[80];
713         struct disk_devdesc devd;
714         bdinfo_t *bd;
715         int i, ret = 0;
716         char drive;
717
718         if (STAILQ_EMPTY(bdi))
719                 return (0);
720
721         printf("%s devices:", dev->dv_name);
722         if ((ret = pager_output("\n")) != 0)
723                 return (ret);
724
725         i = -1;
726         STAILQ_FOREACH(bd, bdi, bd_link) {
727                 i++;
728
729                 switch (dev->dv_type) {
730                 case DEVT_FD:
731                         drive = 'A';
732                         break;
733                 case DEVT_CD:
734                         drive = 'C' + bd_count(&hdinfo);
735                         break;
736                 default:
737                         drive = 'C';
738                         break;
739                 }
740
741                 snprintf(line, sizeof(line),
742                     "    %s%d:   BIOS drive %c (%s%ju X %u):\n",
743                     dev->dv_name, i, drive + i,
744                     (bd->bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA ?
745                     "no media, " : "",
746                     (uintmax_t)bd->bd_sectors,
747                     bd->bd_sectorsize);
748                 if ((ret = pager_output(line)) != 0)
749                         break;
750
751                 if ((bd->bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA)
752                         continue;
753
754                 if (dev->dv_type != DEVT_DISK)
755                         continue;
756
757                 devd.dd.d_dev = dev;
758                 devd.dd.d_unit = i;
759                 devd.d_slice = D_SLICENONE;
760                 devd.d_partition = D_PARTNONE;
761                 if (disk_open(&devd,
762                     bd->bd_sectorsize * bd->bd_sectors,
763                     bd->bd_sectorsize) == 0) {
764                         snprintf(line, sizeof(line), "    %s%d",
765                             dev->dv_name, i);
766                         ret = disk_print(&devd, line, verbose);
767                         disk_close(&devd);
768                         if (ret != 0)
769                                 break;
770                 }
771         }
772         return (ret);
773 }
774
775 static int
776 fd_print(int verbose)
777 {
778         return (bd_print_common(&biosfd, &fdinfo, verbose));
779 }
780
781 static int
782 bd_print(int verbose)
783 {
784         return (bd_print_common(&bioshd, &hdinfo, verbose));
785 }
786
787 static int
788 cd_print(int verbose)
789 {
790         return (bd_print_common(&bioscd, &cdinfo, verbose));
791 }
792
793 /*
794  * Read disk size from partition.
795  * This is needed to work around buggy BIOS systems returning
796  * wrong (truncated) disk media size.
797  * During bd_probe() we tested if the multiplication of bd_sectors
798  * would overflow so it should be safe to perform here.
799  */
800 static uint64_t
801 bd_disk_get_sectors(struct disk_devdesc *dev)
802 {
803         bdinfo_t *bd;
804         struct disk_devdesc disk;
805         uint64_t size;
806
807         bd = bd_get_bdinfo(&dev->dd);
808         if (bd == NULL)
809                 return (0);
810
811         disk.dd.d_dev = dev->dd.d_dev;
812         disk.dd.d_unit = dev->dd.d_unit;
813         disk.d_slice = D_SLICENONE;
814         disk.d_partition = D_PARTNONE;
815         disk.d_offset = 0;
816
817         size = bd->bd_sectors * bd->bd_sectorsize;
818         if (disk_open(&disk, size, bd->bd_sectorsize) == 0) {
819                 (void) disk_ioctl(&disk, DIOCGMEDIASIZE, &size);
820                 disk_close(&disk);
821         }
822         return (size / bd->bd_sectorsize);
823 }
824
825 /*
826  * Attempt to open the disk described by (dev) for use by (f).
827  *
828  * Note that the philosophy here is "give them exactly what
829  * they ask for".  This is necessary because being too "smart"
830  * about what the user might want leads to complications.
831  * (eg. given no slice or partition value, with a disk that is
832  *  sliced - are they after the first BSD slice, or the DOS
833  *  slice before it?)
834  */
835 static int
836 bd_open(struct open_file *f, ...)
837 {
838         bdinfo_t *bd;
839         struct disk_devdesc *dev;
840         va_list ap;
841         int rc;
842
843         va_start(ap, f);
844         dev = va_arg(ap, struct disk_devdesc *);
845         va_end(ap);
846
847         bd = bd_get_bdinfo(&dev->dd);
848         if (bd == NULL)
849                 return (EIO);
850
851         if ((bd->bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA) {
852                 if (!bd_int13probe(bd))
853                         return (EIO);
854                 if ((bd->bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA)
855                         return (EIO);
856         }
857         if (bd->bd_bcache == NULL)
858             bd->bd_bcache = bcache_allocate();
859
860         if (bd->bd_open == 0)
861                 bd->bd_sectors = bd_disk_get_sectors(dev);
862         bd->bd_open++;
863
864         rc = 0;
865         if (dev->dd.d_dev->dv_type == DEVT_DISK) {
866                 rc = disk_open(dev, bd->bd_sectors * bd->bd_sectorsize,
867                     bd->bd_sectorsize);
868                 if (rc != 0) {
869                         bd->bd_open--;
870                         if (bd->bd_open == 0) {
871                                 bcache_free(bd->bd_bcache);
872                                 bd->bd_bcache = NULL;
873                         }
874                 }
875         }
876         return (rc);
877 }
878
879 static int
880 bd_close(struct open_file *f)
881 {
882         struct disk_devdesc *dev;
883         bdinfo_t *bd;
884         int rc = 0;
885
886         dev = (struct disk_devdesc *)f->f_devdata;
887         bd = bd_get_bdinfo(&dev->dd);
888         if (bd == NULL)
889                 return (EIO);
890
891         bd->bd_open--;
892         if (bd->bd_open == 0) {
893             bcache_free(bd->bd_bcache);
894             bd->bd_bcache = NULL;
895         }
896         if (dev->dd.d_dev->dv_type == DEVT_DISK)
897                 rc = disk_close(dev);
898         return (rc);
899 }
900
901 static int
902 bd_ioctl(struct open_file *f, u_long cmd, void *data)
903 {
904         bdinfo_t *bd;
905         struct disk_devdesc *dev;
906         int rc;
907
908         dev = (struct disk_devdesc *)f->f_devdata;
909         bd = bd_get_bdinfo(&dev->dd);
910         if (bd == NULL)
911                 return (EIO);
912
913         if (dev->dd.d_dev->dv_type == DEVT_DISK) {
914                 rc = disk_ioctl(dev, cmd, data);
915                 if (rc != ENOTTY)
916                         return (rc);
917         }
918
919         switch (cmd) {
920         case DIOCGSECTORSIZE:
921                 *(uint32_t *)data = bd->bd_sectorsize;
922                 break;
923         case DIOCGMEDIASIZE:
924                 *(uint64_t *)data = bd->bd_sectors * bd->bd_sectorsize;
925                 break;
926         default:
927                 return (ENOTTY);
928         }
929         return (0);
930 }
931
932 static int
933 bd_strategy(void *devdata, int rw, daddr_t dblk, size_t size,
934     char *buf, size_t *rsize)
935 {
936         bdinfo_t *bd;
937         struct bcache_devdata bcd;
938         struct disk_devdesc *dev;
939         daddr_t offset;
940
941         dev = (struct disk_devdesc *)devdata;
942         bd = bd_get_bdinfo(&dev->dd);
943         if (bd == NULL)
944                 return (EINVAL);
945
946         bcd.dv_strategy = bd_realstrategy;
947         bcd.dv_devdata = devdata;
948         bcd.dv_cache = bd->bd_bcache;
949
950         offset = 0;
951         if (dev->dd.d_dev->dv_type == DEVT_DISK) {
952
953                 offset = dev->d_offset * bd->bd_sectorsize;
954                 offset /= BIOSDISK_SECSIZE;
955         }
956         return (bcache_strategy(&bcd, rw, dblk + offset, size,
957             buf, rsize));
958 }
959
960 static int
961 bd_realstrategy(void *devdata, int rw, daddr_t dblk, size_t size,
962     char *buf, size_t *rsize)
963 {
964         struct disk_devdesc *dev = (struct disk_devdesc *)devdata;
965         bdinfo_t *bd;
966         uint64_t disk_blocks, offset, d_offset;
967         size_t blks, blkoff, bsize, bio_size, rest;
968         caddr_t bbuf = NULL;
969         int rc;
970
971         bd = bd_get_bdinfo(&dev->dd);
972         if (bd == NULL || (bd->bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA)
973                 return (EIO);
974
975         /*
976          * First make sure the IO size is a multiple of 512 bytes. While we do
977          * process partial reads below, the strategy mechanism is built
978          * assuming IO is a multiple of 512B blocks. If the request is not
979          * a multiple of 512B blocks, it has to be some sort of bug.
980          */
981         if (size == 0 || (size % BIOSDISK_SECSIZE) != 0) {
982                 printf("bd_strategy: %d bytes I/O not multiple of %d\n",
983                     size, BIOSDISK_SECSIZE);
984                 return (EIO);
985         }
986
987         DPRINTF("open_disk %p", dev);
988
989         offset = dblk * BIOSDISK_SECSIZE;
990         dblk = offset / bd->bd_sectorsize;
991         blkoff = offset % bd->bd_sectorsize;
992
993         /*
994          * Check the value of the size argument. We do have quite small
995          * heap (64MB), but we do not know good upper limit, so we check against
996          * INT_MAX here. This will also protect us against possible overflows
997          * while translating block count to bytes.
998          */
999         if (size > INT_MAX) {
1000                 DPRINTF("too large I/O: %zu bytes", size);
1001                 return (EIO);
1002         }
1003
1004         blks = size / bd->bd_sectorsize;
1005         if (blks == 0 || (size % bd->bd_sectorsize) != 0)
1006                 blks++;
1007
1008         if (dblk > dblk + blks)
1009                 return (EIO);
1010
1011         if (rsize)
1012                 *rsize = 0;
1013
1014         /*
1015          * Get disk blocks, this value is either for whole disk or for
1016          * partition.
1017          */
1018         d_offset = 0;
1019         disk_blocks = 0;
1020         if (dev->dd.d_dev->dv_type == DEVT_DISK) {
1021                 if (disk_ioctl(dev, DIOCGMEDIASIZE, &disk_blocks) == 0) {
1022                         /* DIOCGMEDIASIZE does return bytes. */
1023                         disk_blocks /= bd->bd_sectorsize;
1024                 }
1025                 d_offset = dev->d_offset;
1026         }
1027         if (disk_blocks == 0)
1028                 disk_blocks = bd->bd_sectors - d_offset;
1029
1030         /* Validate source block address. */
1031         if (dblk < d_offset || dblk >= d_offset + disk_blocks)
1032                 return (EIO);
1033
1034         /*
1035          * Truncate if we are crossing disk or partition end.
1036          */
1037         if (dblk + blks >= d_offset + disk_blocks) {
1038                 blks = d_offset + disk_blocks - dblk;
1039                 size = blks * bd->bd_sectorsize;
1040                 DPRINTF("short I/O %d", blks);
1041         }
1042
1043         bio_size = min(BIO_BUFFER_SIZE, size);
1044         while (bio_size > bd->bd_sectorsize) {
1045                 bbuf = bio_alloc(bio_size);
1046                 if (bbuf != NULL)
1047                         break;
1048                 bio_size -= bd->bd_sectorsize;
1049         }
1050         if (bbuf == NULL) {
1051                 bio_size = V86_IO_BUFFER_SIZE;
1052                 if (bio_size / bd->bd_sectorsize == 0)
1053                         panic("BUG: Real mode buffer is too small");
1054
1055                 /* Use alternate 4k buffer */
1056                 bbuf = PTOV(V86_IO_BUFFER);
1057         }
1058         rest = size;
1059         rc = 0;
1060         while (blks > 0) {
1061                 int x = min(blks, bio_size / bd->bd_sectorsize);
1062
1063                 switch (rw & F_MASK) {
1064                 case F_READ:
1065                         DPRINTF("read %d from %lld to %p", x, dblk, buf);
1066                         bsize = bd->bd_sectorsize * x - blkoff;
1067                         if (rest < bsize)
1068                                 bsize = rest;
1069
1070                         if ((rc = bd_io(dev, bd, dblk, x, bbuf, BD_RD)) != 0) {
1071                                 rc = EIO;
1072                                 goto error;
1073                         }
1074
1075                         bcopy(bbuf + blkoff, buf, bsize);
1076                         break;
1077                 case F_WRITE :
1078                         DPRINTF("write %d from %lld to %p", x, dblk, buf);
1079                         if (blkoff != 0) {
1080                                 /*
1081                                  * We got offset to sector, read 1 sector to
1082                                  * bbuf.
1083                                  */
1084                                 x = 1;
1085                                 bsize = bd->bd_sectorsize - blkoff;
1086                                 bsize = min(bsize, rest);
1087                                 rc = bd_io(dev, bd, dblk, x, bbuf, BD_RD);
1088                         } else if (rest < bd->bd_sectorsize) {
1089                                 /*
1090                                  * The remaining block is not full
1091                                  * sector. Read 1 sector to bbuf.
1092                                  */
1093                                 x = 1;
1094                                 bsize = rest;
1095                                 rc = bd_io(dev, bd, dblk, x, bbuf, BD_RD);
1096                         } else {
1097                                 /* We can write full sector(s). */
1098                                 bsize = bd->bd_sectorsize * x;
1099                         }
1100                         /*
1101                          * Put your Data In, Put your Data out,
1102                          * Put your Data In, and shake it all about
1103                          */
1104                         bcopy(buf, bbuf + blkoff, bsize);
1105                         if ((rc = bd_io(dev, bd, dblk, x, bbuf, BD_WR)) != 0) {
1106                                 rc = EIO;
1107                                 goto error;
1108                         }
1109
1110                         break;
1111                 default:
1112                         /* DO NOTHING */
1113                         rc = EROFS;
1114                         goto error;
1115                 }
1116
1117                 blkoff = 0;
1118                 buf += bsize;
1119                 rest -= bsize;
1120                 blks -= x;
1121                 dblk += x;
1122         }
1123
1124         if (rsize != NULL)
1125                 *rsize = size;
1126 error:
1127         if (bbuf != PTOV(V86_IO_BUFFER))
1128                 bio_free(bbuf, bio_size);
1129         return (rc);
1130 }
1131
1132 static int
1133 bd_edd_io(bdinfo_t *bd, daddr_t dblk, int blks, caddr_t dest,
1134     int dowrite)
1135 {
1136         static struct edd_packet packet;
1137
1138         packet.len = sizeof(struct edd_packet);
1139         packet.count = blks;
1140         packet.off = VTOPOFF(dest);
1141         packet.seg = VTOPSEG(dest);
1142         packet.lba = dblk;
1143         v86.ctl = V86_FLAGS;
1144         v86.addr = DISK_BIOS;
1145         if (dowrite == BD_WR)
1146                 v86.eax = CMD_WRITE_LBA; /* maybe Write with verify 0x4302? */
1147         else
1148                 v86.eax = CMD_READ_LBA;
1149         v86.edx = bd->bd_unit;
1150         v86.ds = VTOPSEG(&packet);
1151         v86.esi = VTOPOFF(&packet);
1152         v86int();
1153         if (V86_CY(v86.efl))
1154                 return (v86.eax >> 8);
1155         return (0);
1156 }
1157
1158 static int
1159 bd_chs_io(bdinfo_t *bd, daddr_t dblk, int blks, caddr_t dest,
1160     int dowrite)
1161 {
1162         uint32_t x, bpc, cyl, hd, sec;
1163
1164         bpc = bd->bd_sec * bd->bd_hds;  /* blocks per cylinder */
1165         x = dblk;
1166         cyl = x / bpc;                  /* block # / blocks per cylinder */
1167         x %= bpc;                               /* block offset into cylinder */
1168         hd = x / bd->bd_sec;            /* offset / blocks per track */
1169         sec = x % bd->bd_sec;           /* offset into track */
1170
1171         /* correct sector number for 1-based BIOS numbering */
1172         sec++;
1173
1174         if (cyl > 1023) {
1175                 /* CHS doesn't support cylinders > 1023. */
1176                 return (1);
1177         }
1178
1179         v86.ctl = V86_FLAGS;
1180         v86.addr = DISK_BIOS;
1181         if (dowrite == BD_WR)
1182                 v86.eax = CMD_WRITE_CHS | blks;
1183         else
1184                 v86.eax = CMD_READ_CHS | blks;
1185         v86.ecx = ((cyl & 0xff) << 8) | ((cyl & 0x300) >> 2) | sec;
1186         v86.edx = (hd << 8) | bd->bd_unit;
1187         v86.es = VTOPSEG(dest);
1188         v86.ebx = VTOPOFF(dest);
1189         v86int();
1190         if (V86_CY(v86.efl))
1191                 return (v86.eax >> 8);
1192         return (0);
1193 }
1194
1195 static void
1196 bd_io_workaround(bdinfo_t *bd)
1197 {
1198         uint8_t buf[8 * 1024];
1199
1200         bd_edd_io(bd, 0xffffffff, 1, (caddr_t)buf, BD_RD);
1201 }
1202
1203 static int
1204 bd_io(struct disk_devdesc *dev, bdinfo_t *bd, daddr_t dblk, int blks,
1205     caddr_t dest, int dowrite)
1206 {
1207         int result, retry;
1208
1209         /* Just in case some idiot actually tries to read/write -1 blocks... */
1210         if (blks < 0)
1211                 return (-1);
1212
1213         /*
1214          * Workaround for a problem with some HP ProLiant BIOS failing to work
1215          * out the boot disk after installation. hrs and kuriyama discovered
1216          * this problem with an HP ProLiant DL320e Gen 8 with a 3TB HDD, and
1217          * discovered that an int13h call seems to cause a buffer overrun in
1218          * the bios. The problem is alleviated by doing an extra read before
1219          * the buggy read. It is not immediately known whether other models
1220          * are similarly affected.
1221          * Loop retrying the operation a couple of times.  The BIOS
1222          * may also retry.
1223          */
1224         if (dowrite == BD_RD && dblk >= 0x100000000)
1225                 bd_io_workaround(bd);
1226         for (retry = 0; retry < 3; retry++) {
1227                 if (bd->bd_flags & BD_MODEEDD)
1228                         result = bd_edd_io(bd, dblk, blks, dest, dowrite);
1229                 else
1230                         result = bd_chs_io(bd, dblk, blks, dest, dowrite);
1231
1232                 if (result == 0) {
1233                         if (bd->bd_flags & BD_NO_MEDIA)
1234                                 bd->bd_flags &= ~BD_NO_MEDIA;
1235                         break;
1236                 }
1237
1238                 bd_reset_disk(bd->bd_unit);
1239
1240                 /*
1241                  * Error codes:
1242                  * 20h  controller failure
1243                  * 31h  no media in drive (IBM/MS INT 13 extensions)
1244                  * 80h  no media in drive, VMWare (Fusion)
1245                  * There is no reason to repeat the IO with errors above.
1246                  */
1247                 if (result == 0x20 || result == 0x31 || result == 0x80) {
1248                         bd->bd_flags |= BD_NO_MEDIA;
1249                         break;
1250                 }
1251         }
1252
1253         if (result != 0 && (bd->bd_flags & BD_NO_MEDIA) == 0) {
1254                 if (dowrite == BD_WR) {
1255                         printf("%s%d: Write %d sector(s) from %p (0x%x) "
1256                             "to %lld: 0x%x\n", dev->dd.d_dev->dv_name,
1257                             dev->dd.d_unit, blks, dest, VTOP(dest), dblk,
1258                             result);
1259                 } else {
1260                         printf("%s%d: Read %d sector(s) from %lld to %p "
1261                             "(0x%x): 0x%x\n", dev->dd.d_dev->dv_name,
1262                             dev->dd.d_unit, blks, dblk, dest, VTOP(dest),
1263                             result);
1264                 }
1265         }
1266
1267         return (result);
1268 }
1269
1270 /*
1271  * Return the BIOS geometry of a given "fixed drive" in a format
1272  * suitable for the legacy bootinfo structure.  Since the kernel is
1273  * expecting raw int 0x13/0x8 values for N_BIOS_GEOM drives, we
1274  * prefer to get the information directly, rather than rely on being
1275  * able to put it together from information already maintained for
1276  * different purposes and for a probably different number of drives.
1277  *
1278  * For valid drives, the geometry is expected in the format (31..0)
1279  * "000000cc cccccccc hhhhhhhh 00ssssss"; and invalid drives are
1280  * indicated by returning the geometry of a "1.2M" PC-format floppy
1281  * disk.  And, incidentally, what is returned is not the geometry as
1282  * such but the highest valid cylinder, head, and sector numbers.
1283  */
1284 uint32_t
1285 bd_getbigeom(int bunit)
1286 {
1287
1288         v86.ctl = V86_FLAGS;
1289         v86.addr = DISK_BIOS;
1290         v86.eax = CMD_READ_PARAM;
1291         v86.edx = 0x80 + bunit;
1292         v86int();
1293         if (V86_CY(v86.efl))
1294                 return (0x4f010f);
1295         return (((v86.ecx & 0xc0) << 18) | ((v86.ecx & 0xff00) << 8) |
1296             (v86.edx & 0xff00) | (v86.ecx & 0x3f));
1297 }
1298
1299 /*
1300  * Return a suitable dev_t value for (dev).
1301  *
1302  * In the case where it looks like (dev) is a SCSI disk, we allow the number of
1303  * IDE disks to be specified in $num_ide_disks.  There should be a Better Way.
1304  */
1305 int
1306 bd_getdev(struct i386_devdesc *d)
1307 {
1308         struct disk_devdesc *dev;
1309         bdinfo_t *bd;
1310         int     biosdev;
1311         int     major;
1312         int     rootdev;
1313         char    *nip, *cp;
1314         int     i, unit, slice, partition;
1315
1316         /* XXX: Assume partition 'a'. */
1317         slice = 0;
1318         partition = 0;
1319
1320         dev = (struct disk_devdesc *)d;
1321         bd = bd_get_bdinfo(&dev->dd);
1322         if (bd == NULL)
1323                 return (-1);
1324
1325         biosdev = bd_unit2bios(d);
1326         DPRINTF("unit %d BIOS device %d", dev->dd.d_unit, biosdev);
1327         if (biosdev == -1)                      /* not a BIOS device */
1328                 return (-1);
1329
1330         if (dev->dd.d_dev->dv_type == DEVT_DISK) {
1331                 if (disk_open(dev, bd->bd_sectors * bd->bd_sectorsize,
1332                     bd->bd_sectorsize) != 0)    /* oops, not a viable device */
1333                         return (-1);
1334                 else
1335                         disk_close(dev);
1336                 slice = dev->d_slice + 1;
1337                 partition = dev->d_partition;
1338         }
1339
1340         if (biosdev < 0x80) {
1341                 /* floppy (or emulated floppy) or ATAPI device */
1342                 if (bd->bd_type == DT_ATAPI) {
1343                         /* is an ATAPI disk */
1344                         major = WFDMAJOR;
1345                 } else {
1346                         /* is a floppy disk */
1347                         major = FDMAJOR;
1348                 }
1349         } else {
1350                 /* assume an IDE disk */
1351                 major = WDMAJOR;
1352         }
1353         /* default root disk unit number */
1354         unit = biosdev & 0x7f;
1355
1356         if (dev->dd.d_dev->dv_type == DEVT_CD) {
1357                 /*
1358                  * XXX: Need to examine device spec here to figure out if
1359                  * SCSI or ATAPI.  No idea on how to figure out device number.
1360                  * All we can really pass to the kernel is what bus and device
1361                  * on which bus we were booted from, which dev_t isn't well
1362                  * suited to since those number don't match to unit numbers
1363                  * very well.  We may just need to engage in a hack where
1364                  * we pass -C to the boot args if we are the boot device.
1365                  */
1366                 major = ACDMAJOR;
1367                 unit = 0;       /* XXX */
1368         }
1369
1370         /* XXX a better kludge to set the root disk unit number */
1371         if ((nip = getenv("root_disk_unit")) != NULL) {
1372                 i = strtol(nip, &cp, 0);
1373                 /* check for parse error */
1374                 if ((cp != nip) && (*cp == 0))
1375                         unit = i;
1376         }
1377
1378         rootdev = MAKEBOOTDEV(major, slice, unit, partition);
1379         DPRINTF("dev is 0x%x\n", rootdev);
1380         return (rootdev);
1381 }