Sync usage with man page.
[netbsd-mini2440.git] / sys / arch / zaurus / stand / zboot / diskprobe.c
blob7741a766dd9c1868b097ae47256f21a62da9a0f8
1 /* $NetBSD$ */
2 /* $OpenBSD: diskprobe.c,v 1.3 2006/10/13 00:00:55 krw Exp $ */
4 /*
5 * Copyright (c) 1997 Tobias Weingartner
6 * All rights reserved.
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.
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
27 * SUCH DAMAGE.
31 /* We want the disk type names from disklabel.h */
32 #undef DKTYPENAMES
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>
40 #include "boot.h"
41 #include "disk.h"
42 #include "unixdev.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.
59 static void
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];
65 struct diskinfo *dip;
66 u_int disk = 0;
67 u_int hd_disk = 0;
68 u_int mmcd_disk = 0;
69 uint unit = 0;
70 int first = 1;
71 int i;
73 buf[0] = '\0';
75 /* Hard disks */
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) {
81 dealloc(dip, 0);
82 continue;
85 bios_devname(order[i], devname, sizeof(devname));
86 if (order[i] & 0x80) {
87 unit = hd_disk;
88 snprintf(dip->devname, sizeof(dip->devname), "%s%d",
89 devname, hd_disk++);
90 } else {
91 unit = mmcd_disk;
92 snprintf(dip->devname, sizeof(dip->devname), "%s%d",
93 devname, mmcd_disk++);
95 strlcat(buf, dip->devname, bufsiz);
96 disk++;
98 /* Try to find the label, to figure out device type. */
99 if (bios_getdisklabel(&dip->bios_info, &dip->disklabel)
100 == NULL) {
101 strlcat(buf, "*", bufsiz);
102 if (first) {
103 first = 0;
104 strlcpy(disk_devname, devname,
105 sizeof(disk_devname));
106 default_devname = disk_devname;
107 default_unit = unit;
109 } else {
110 /* Best guess */
111 switch (dip->disklabel.d_type) {
112 case DTYPE_SCSI:
113 case DTYPE_ESDI:
114 case DTYPE_ST506:
115 dip->bios_info.flags |= BDI_GOODLABEL;
116 break;
118 default:
119 dip->bios_info.flags |= BDI_BADLABEL;
123 /* Add to queue of disks. */
124 TAILQ_INSERT_TAIL(&disklist, dip, list);
126 strlcat(buf, " ", bufsiz);
128 if (disk == 0)
129 strlcat(buf, "none...", bufsiz);
132 /* Probe for all BIOS supported disks */
133 void
134 diskprobe(char *buf, size_t bufsiz)
137 /* Init stuff */
138 TAILQ_INIT(&disklist);
140 /* Do probes */
141 hardprobe(buf, bufsiz);
145 * Find info on the disk given by major + unit number.
147 struct diskinfo *
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) {
157 return dip;
160 return NULL;
164 bios_devname(int biosdev, char *devname, int size)
167 if ((biosdev & 0x80) != 0) {
168 strlcpy(devname, devname_hd, size);
169 } else {
170 strlcpy(devname, devname_mmcd, size);
172 return 0;
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.
179 void
180 bios_devpath(int dev, int part, char *p)
182 char devname[MAXDEVNAME];
183 const char *q;
185 *p++ = '/';
186 *p++ = 'd';
187 *p++ = 'e';
188 *p++ = 'v';
189 *p++ = '/';
191 bios_devname(dev, devname, sizeof(devname));
192 q = devname;
193 while (*q != '\0')
194 *p++ = *q++;
196 *p++ = 'a' + (dev & 0x7f);
197 if (part >= 0)
198 *p++ = '1' + part;
199 *p = '\0';
203 * Fill out a bios_diskinfo_t for this device.
205 char *
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";
224 return NULL;
228 bios_getdospart(bios_diskinfo_t *bdi)
230 char path[PATH_MAX];
231 char buf[DEV_BSIZE];
232 struct mbr_partition *mp;
233 int fd;
234 u_int part;
235 size_t rsize;
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) {
245 timeout--;
246 sleep(1);
247 fd = uopen(path, LINUX_O_RDONLY);
249 if (fd != -1)
250 sleep(2);
252 if (fd == -1)
253 return -1;
255 /* Read the disk's MBR. */
256 if (unixstrategy((void *)fd, F_READ, MBR_BBSECTOR, DEV_BSIZE, buf,
257 &rsize) != 0 || rsize != DEV_BSIZE) {
258 uclose(fd);
259 errno = EIO;
260 return -1;
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)
267 break;
269 if (part == MBR_PART_COUNT) {
270 uclose(fd);
271 errno = ERDLAB;
272 return -1;
274 uclose(fd);
276 return part;
279 char *
280 bios_getdisklabel(bios_diskinfo_t *bdi, struct disklabel *label)
282 char path[PATH_MAX];
283 char buf[DEV_BSIZE];
284 int part;
285 int fd;
286 size_t rsize;
288 part = bios_getdospart(bdi);
289 if (part < 0)
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);
301 uclose(fd);
302 /* Don't wait for other disks if this label is ok. */
303 if (msg == NULL)
304 timeout = 0;
305 return msg;
308 return "failed to open partition";