2 /* $OpenBSD: diskprobe.c,v 1.3 2006/10/13 00:00:55 krw Exp $ */
5 * Copyright (c) 1997 Tobias Weingartner
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 /* We want the disk type names from disklabel.h */
34 #include <sys/param.h>
35 #include <sys/bootblock.h>
36 #include <sys/disklabel.h>
37 #include <sys/queue.h>
38 #include <sys/reboot.h>
43 #include "compat_linux.h"
45 /* Disk spin-up wait timeout. */
46 static u_int timeout
= 10;
48 /* Local Prototypes */
49 static void hardprobe(char *buf
, size_t bufsiz
);
51 /* List of disk devices we found/probed */
52 struct disklist_lh disklist
;
54 static char disk_devname
[MAXDEVNAME
];
57 * Probe for all hard disks.
60 hardprobe(char *buf
, size_t bufsiz
)
62 /* XXX probe disks in this order */
63 static const int order
[] = { 0x80, 0x82, 0x00 };
64 char devname
[MAXDEVNAME
];
76 for (i
= 0; i
< __arraycount(order
); i
++) {
77 dip
= alloc(sizeof(struct diskinfo
));
78 memset(dip
, 0, sizeof(*dip
));
80 if (bios_getdiskinfo(order
[i
], &dip
->bios_info
) != NULL
) {
85 bios_devname(order
[i
], devname
, sizeof(devname
));
86 if (order
[i
] & 0x80) {
88 snprintf(dip
->devname
, sizeof(dip
->devname
), "%s%d",
92 snprintf(dip
->devname
, sizeof(dip
->devname
), "%s%d",
93 devname
, mmcd_disk
++);
95 strlcat(buf
, dip
->devname
, bufsiz
);
98 /* Try to find the label, to figure out device type. */
99 if (bios_getdisklabel(&dip
->bios_info
, &dip
->disklabel
)
101 strlcat(buf
, "*", bufsiz
);
104 strlcpy(disk_devname
, devname
,
105 sizeof(disk_devname
));
106 default_devname
= disk_devname
;
111 switch (dip
->disklabel
.d_type
) {
115 dip
->bios_info
.flags
|= BDI_GOODLABEL
;
119 dip
->bios_info
.flags
|= BDI_BADLABEL
;
123 /* Add to queue of disks. */
124 TAILQ_INSERT_TAIL(&disklist
, dip
, list
);
126 strlcat(buf
, " ", bufsiz
);
129 strlcat(buf
, "none...", bufsiz
);
132 /* Probe for all BIOS supported disks */
134 diskprobe(char *buf
, size_t bufsiz
)
138 TAILQ_INIT(&disklist
);
141 hardprobe(buf
, bufsiz
);
145 * Find info on the disk given by major + unit number.
148 dkdevice(const char *devname
, uint unit
)
150 char name
[MAXDEVNAME
];
151 struct diskinfo
*dip
;
153 snprintf(name
, sizeof(name
), "%s%d", devname
, unit
);
154 for (dip
= TAILQ_FIRST(&disklist
); dip
!= NULL
;
155 dip
= TAILQ_NEXT(dip
, list
)) {
156 if (strcmp(name
, dip
->devname
) == 0) {
164 bios_devname(int biosdev
, char *devname
, int size
)
167 if ((biosdev
& 0x80) != 0) {
168 strlcpy(devname
, devname_hd
, size
);
170 strlcpy(devname
, devname_mmcd
, size
);
176 * Find the Linux device path that corresponds to the given "BIOS" disk,
177 * where 0x80 corresponds to /dev/hda, 0x81 to /dev/hdb, and so on.
180 bios_devpath(int dev
, int part
, char *p
)
182 char devname
[MAXDEVNAME
];
191 bios_devname(dev
, devname
, sizeof(devname
));
196 *p
++ = 'a' + (dev
& 0x7f);
203 * Fill out a bios_diskinfo_t for this device.
206 bios_getdiskinfo(int dev
, bios_diskinfo_t
*bdi
)
208 static char path
[PATH_MAX
];
209 struct linux_stat sb
;
211 memset(bdi
, 0, sizeof *bdi
);
212 bdi
->bios_number
= -1;
214 bios_devpath(dev
, -1, path
);
216 if (ustat(path
, &sb
) != 0)
217 return "no device node";
219 bdi
->bios_number
= dev
;
221 if (bios_getdospart(bdi
) < 0)
222 return "no NetBSD partition";
228 bios_getdospart(bios_diskinfo_t
*bdi
)
232 struct mbr_partition
*mp
;
237 bios_devpath(bdi
->bios_number
, -1, path
);
240 * Give disk devices some time to become ready when the first open
241 * fails. Even when open succeeds the disk is sometimes not ready.
243 if ((fd
= uopen(path
, LINUX_O_RDONLY
)) == -1 && errno
== ENXIO
) {
244 while (fd
== -1 && timeout
> 0) {
247 fd
= uopen(path
, LINUX_O_RDONLY
);
255 /* Read the disk's MBR. */
256 if (unixstrategy((void *)fd
, F_READ
, MBR_BBSECTOR
, DEV_BSIZE
, buf
,
257 &rsize
) != 0 || rsize
!= DEV_BSIZE
) {
263 /* Find NetBSD primary partition in the disk's MBR. */
264 mp
= (struct mbr_partition
*)&buf
[MBR_PART_OFFSET
];
265 for (part
= 0; part
< MBR_PART_COUNT
; part
++) {
266 if (mp
[part
].mbrp_type
== MBR_PTYPE_NETBSD
)
269 if (part
== MBR_PART_COUNT
) {
280 bios_getdisklabel(bios_diskinfo_t
*bdi
, struct disklabel
*label
)
288 part
= bios_getdospart(bdi
);
290 return "no NetBSD partition";
292 bios_devpath(bdi
->bios_number
, part
, path
);
294 /* Test if the NetBSD partition has a valid disklabel. */
295 if ((fd
= uopen(path
, LINUX_O_RDONLY
)) != -1) {
296 char *msg
= "failed to read disklabel";
298 if (unixstrategy((void *)fd
, F_READ
, LABELSECTOR
,
299 DEV_BSIZE
, buf
, &rsize
) == 0 && rsize
== DEV_BSIZE
)
300 msg
= getdisklabel(buf
, label
);
302 /* Don't wait for other disks if this label is ok. */
308 return "failed to open partition";