Annotation of sys/arch/i386/stand/libsa/diskprobe.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: diskprobe.c,v 1.29 2007/06/18 22:11:20 krw Exp $ */
2:
3: /*
4: * Copyright (c) 1997 Tobias Weingartner
5: * All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: *
16: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
20: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26: * SUCH DAMAGE.
27: *
28: */
29:
30: /* We want the disk type names from disklabel.h */
31: #undef DKTYPENAMES
32:
33: #include <sys/param.h>
34: #include <sys/queue.h>
35: #include <sys/reboot.h>
36: #include <sys/disklabel.h>
37: #include <stand/boot/bootarg.h>
38: #include <machine/biosvar.h>
39: #include <lib/libz/zlib.h>
40: #include "disk.h"
41: #include "biosdev.h"
42: #include "libsa.h"
43:
44: #define MAX_CKSUMLEN MAXBSIZE / DEV_BSIZE /* Max # of blks to cksum */
45:
46: /* Local Prototypes */
47: static int disksum(int);
48:
49: /* List of disk devices we found/probed */
50: struct disklist_lh disklist;
51:
52: /* Pointer to boot device */
53: struct diskinfo *bootdev_dip;
54:
55: extern int debug;
56: extern int bios_bootdev;
57: extern int bios_cddev;
58:
59: /* Probe for all BIOS floppies */
60: static void
61: floppyprobe(void)
62: {
63: struct diskinfo *dip;
64: int i;
65:
66: /* Floppies */
67: for (i = 0; i < 4; i++) {
68: dip = alloc(sizeof(struct diskinfo));
69: bzero(dip, sizeof(*dip));
70:
71: if (bios_getdiskinfo(i, &dip->bios_info)) {
72: #ifdef BIOS_DEBUG
73: if (debug)
74: printf(" <!fd%u>", i);
75: #endif
76: free(dip, 0);
77: break;
78: }
79:
80: printf(" fd%u", i);
81:
82: /* Fill out best we can - (fd?) */
83: dip->bios_info.bsd_dev = MAKEBOOTDEV(2, 0, 0, i, RAW_PART);
84:
85: /*
86: * Delay reading the disklabel until we're sure we want
87: * to boot from the floppy. Doing this avoids a delay
88: * (sometimes very long) when trying to read the label
89: * and the drive is unplugged.
90: */
91: dip->bios_info.flags |= BDI_BADLABEL;
92:
93: /* Add to queue of disks */
94: TAILQ_INSERT_TAIL(&disklist, dip, list);
95: }
96: }
97:
98:
99: /* Probe for all BIOS hard disks */
100: static void
101: hardprobe(void)
102: {
103: struct diskinfo *dip;
104: int i;
105: u_int bsdunit, type;
106: u_int scsi = 0, ide = 0;
107: const char *dc = (const char *)((0x40 << 4) + 0x75);
108:
109: /* Hard disks */
110: for (i = 0x80; i < (0x80 + *dc); i++) {
111: dip = alloc(sizeof(struct diskinfo));
112: bzero(dip, sizeof(*dip));
113:
114: if (bios_getdiskinfo(i, &dip->bios_info)) {
115: #ifdef BIOS_DEBUG
116: if (debug)
117: printf(" <!hd%u>", i&0x7f);
118: #endif
119: free(dip, 0);
120: break;
121: }
122:
123: printf(" hd%u%s", i&0x7f, (dip->bios_info.bios_edd > 0?"+":""));
124:
125: /* Try to find the label, to figure out device type */
126: if ((bios_getdisklabel(&dip->bios_info, &dip->disklabel)) ) {
127: printf("*");
128: bsdunit = ide++;
129: type = 0; /* XXX let it be IDE */
130: } else {
131: /* Best guess */
132: switch (dip->disklabel.d_type) {
133: case DTYPE_SCSI:
134: type = 4;
135: bsdunit = scsi++;
136: dip->bios_info.flags |= BDI_GOODLABEL;
137: break;
138:
139: case DTYPE_ESDI:
140: case DTYPE_ST506:
141: type = 0;
142: bsdunit = ide++;
143: dip->bios_info.flags |= BDI_GOODLABEL;
144: break;
145:
146: default:
147: dip->bios_info.flags |= BDI_BADLABEL;
148: type = 0; /* XXX Suggest IDE */
149: bsdunit = ide++;
150: }
151: }
152:
153: dip->bios_info.checksum = 0; /* just in case */
154: /* Fill out best we can */
155: dip->bios_info.bsd_dev =
156: MAKEBOOTDEV(type, 0, 0, bsdunit, RAW_PART);
157:
158: /* Add to queue of disks */
159: TAILQ_INSERT_TAIL(&disklist, dip, list);
160: }
161: }
162:
163:
164: /* Probe for all BIOS supported disks */
165: u_int32_t bios_cksumlen;
166: void
167: diskprobe(void)
168: {
169: struct diskinfo *dip;
170: int i;
171:
172: /* These get passed to kernel */
173: bios_diskinfo_t *bios_diskinfo;
174:
175: /* Init stuff */
176: TAILQ_INIT(&disklist);
177:
178: /* Do probes */
179: floppyprobe();
180: #ifdef BIOS_DEBUG
181: if (debug)
182: printf(";");
183: #endif
184: hardprobe();
185:
186: /* Checksumming of hard disks */
187: for (i = 0; disksum(i++) && i < MAX_CKSUMLEN; )
188: ;
189: bios_cksumlen = i;
190:
191: /* Get space for passing bios_diskinfo stuff to kernel */
192: for (i = 0, dip = TAILQ_FIRST(&disklist); dip;
193: dip = TAILQ_NEXT(dip, list))
194: i++;
195: bios_diskinfo = alloc(++i * sizeof(bios_diskinfo_t));
196:
197: /* Copy out the bios_diskinfo stuff */
198: for (i = 0, dip = TAILQ_FIRST(&disklist); dip;
199: dip = TAILQ_NEXT(dip, list))
200: bios_diskinfo[i++] = dip->bios_info;
201:
202: bios_diskinfo[i++].bios_number = -1;
203: /* Register for kernel use */
204: addbootarg(BOOTARG_CKSUMLEN, sizeof(u_int32_t), &bios_cksumlen);
205: addbootarg(BOOTARG_DISKINFO, i * sizeof(bios_diskinfo_t),
206: bios_diskinfo);
207: }
208:
209:
210: void
211: cdprobe(void)
212: {
213: struct diskinfo *dip;
214: int cddev = bios_cddev & 0xff;
215:
216: /* Another BIOS boot device... */
217:
218: if (bios_cddev == -1) /* Not been set, so don't use */
219: return;
220:
221: dip = alloc(sizeof(struct diskinfo));
222: bzero(dip, sizeof(*dip));
223:
224: #if 0
225: if (bios_getdiskinfo(cddev, &dip->bios_info)) {
226: printf(" <!cd0>"); /* XXX */
227: free(dip, 0);
228: return;
229: }
230: #endif
231:
232: printf(" cd0");
233:
234: dip->bios_info.bios_number = cddev;
235: dip->bios_info.bios_edd = 1; /* Use the LBA calls */
236: dip->bios_info.flags |= BDI_GOODLABEL | BDI_EL_TORITO;
237: dip->bios_info.checksum = 0; /* just in case */
238: dip->bios_info.bsd_dev =
239: MAKEBOOTDEV(0, 0, 0, 0xff, RAW_PART);
240:
241: /* Create an imaginary disk label */
242: dip->disklabel.d_secsize = 2048;
243: dip->disklabel.d_ntracks = 1;
244: dip->disklabel.d_nsectors = 100;
245: dip->disklabel.d_ncylinders = 1;
246: dip->disklabel.d_secpercyl = dip->disklabel.d_ntracks *
247: dip->disklabel.d_nsectors;
248: if (dip->disklabel.d_secpercyl == 0) {
249: dip->disklabel.d_secpercyl = 100;
250: /* as long as it's not 0, since readdisklabel divides by it */
251: }
252:
253: strncpy(dip->disklabel.d_typename, "ATAPI CD-ROM",
254: sizeof(dip->disklabel.d_typename));
255: dip->disklabel.d_type = DTYPE_ATAPI;
256:
257: strncpy(dip->disklabel.d_packname, "fictitious",
258: sizeof(dip->disklabel.d_packname));
259: dip->disklabel.d_secperunit = 100;
260: dip->disklabel.d_rpm = 300;
261: dip->disklabel.d_interleave = 1;
262:
263: dip->disklabel.d_bbsize = 2048;
264: dip->disklabel.d_sbsize = 2048;
265:
266: /* 'a' partition covering the "whole" disk */
267: dip->disklabel.d_partitions[0].p_offset = 0;
268: dip->disklabel.d_partitions[0].p_size = 100;
269: dip->disklabel.d_partitions[0].p_fstype = FS_UNUSED;
270:
271: /* The raw partition is special */
272: dip->disklabel.d_partitions[RAW_PART].p_offset = 0;
273: dip->disklabel.d_partitions[RAW_PART].p_size = 100;
274: dip->disklabel.d_partitions[RAW_PART].p_fstype = FS_UNUSED;
275:
276: dip->disklabel.d_npartitions = RAW_PART + 1;
277:
278: dip->disklabel.d_magic = DISKMAGIC;
279: dip->disklabel.d_magic2 = DISKMAGIC;
280: dip->disklabel.d_checksum = dkcksum(&dip->disklabel);
281:
282: /* Add to queue of disks */
283: TAILQ_INSERT_TAIL(&disklist, dip, list);
284: }
285:
286:
287: /* Find info on given BIOS disk */
288: struct diskinfo *
289: dklookup(int dev)
290: {
291: struct diskinfo *dip;
292:
293: for (dip = TAILQ_FIRST(&disklist); dip; dip = TAILQ_NEXT(dip, list))
294: if (dip->bios_info.bios_number == dev)
295: return dip;
296:
297: return NULL;
298: }
299:
300: void
301: dump_diskinfo(void)
302: {
303: struct diskinfo *dip;
304:
305: printf("Disk\tBIOS#\tType\tCyls\tHeads\tSecs\tFlags\tChecksum\n");
306: for (dip = TAILQ_FIRST(&disklist); dip; dip = TAILQ_NEXT(dip, list)) {
307: bios_diskinfo_t *bdi = &dip->bios_info;
308: int d = bdi->bios_number;
309: int u = d & 0x7f;
310: char c;
311:
312: if (bdi->flags & BDI_EL_TORITO) {
313: c = 'c';
314: u = 0;
315: } else {
316: c = (d & 0x80) ? 'h' : 'f';
317: }
318:
319: printf("%cd%d\t0x%x\t%s\t%d\t%d\t%d\t0x%x\t0x%x\n",
320: c, u, d,
321: (bdi->flags & BDI_BADLABEL)?"*none*":"label",
322: bdi->bios_cylinders, bdi->bios_heads, bdi->bios_sectors,
323: bdi->flags, bdi->checksum);
324: }
325: }
326:
327: /* Find BIOS portion on given BIOS disk
328: * XXX - Use dklookup() instead.
329: */
330: bios_diskinfo_t *
331: bios_dklookup(int dev)
332: {
333: struct diskinfo *dip;
334:
335: dip = dklookup(dev);
336: if (dip)
337: return &dip->bios_info;
338:
339: return NULL;
340: }
341:
342: /*
343: * Checksum one more block on all harddrives
344: *
345: * Use the adler32() function from libz,
346: * as it is quick, small, and available.
347: */
348: int
349: disksum(int blk)
350: {
351: struct diskinfo *dip, *dip2;
352: int st, reprobe = 0;
353: char *buf;
354:
355: buf = alloca(DEV_BSIZE);
356: for (dip = TAILQ_FIRST(&disklist); dip; dip = TAILQ_NEXT(dip, list)) {
357: bios_diskinfo_t *bdi = &dip->bios_info;
358:
359: /* Skip this disk if it is not a HD or has had an I/O error */
360: if (!(bdi->bios_number & 0x80) || bdi->flags & BDI_INVALID)
361: continue;
362:
363: /* Adler32 checksum */
364: st = biosd_io(F_READ, bdi, blk, 1, buf);
365: if (st) {
366: bdi->flags |= BDI_INVALID;
367: continue;
368: }
369: bdi->checksum = adler32(bdi->checksum, buf, DEV_BSIZE);
370:
371: for (dip2 = TAILQ_FIRST(&disklist); dip2 != dip;
372: dip2 = TAILQ_NEXT(dip2, list)) {
373: bios_diskinfo_t *bd = &dip2->bios_info;
374: if ((bd->bios_number & 0x80) &&
375: !(bd->flags & BDI_INVALID) &&
376: bdi->checksum == bd->checksum)
377: reprobe = 1;
378: }
379: }
380:
381: return reprobe;
382: }
CVSweb