Annotation of sys/arch/amd64/stand/libsa/diskprobe.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: diskprobe.c,v 1.5 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 = MAKEBOOTDEV(type, 0, 0, bsdunit, RAW_PART);
156:
157: /* Add to queue of disks */
158: TAILQ_INSERT_TAIL(&disklist, dip, list);
159: }
160: }
161:
162:
163: /* Probe for all BIOS supported disks */
164: u_int32_t bios_cksumlen;
165: void
166: diskprobe(void)
167: {
168: struct diskinfo *dip;
169: int i;
170:
171: /* These get passed to kernel */
172: bios_diskinfo_t *bios_diskinfo;
173:
174: /* Init stuff */
175: TAILQ_INIT(&disklist);
176:
177: /* Do probes */
178: floppyprobe();
179: #ifdef BIOS_DEBUG
180: if (debug)
181: printf(";");
182: #endif
183: hardprobe();
184:
185: /* Checksumming of hard disks */
186: for (i = 0; disksum(i++) && i < MAX_CKSUMLEN; )
187: ;
188: bios_cksumlen = i;
189:
190: /* Get space for passing bios_diskinfo stuff to kernel */
191: for(i = 0, dip = TAILQ_FIRST(&disklist); dip; dip = TAILQ_NEXT(dip, list))
192: i++;
193: bios_diskinfo = alloc(++i * sizeof(bios_diskinfo_t));
194:
195: /* Copy out the bios_diskinfo stuff */
196: for(i = 0, dip = TAILQ_FIRST(&disklist); dip; dip = TAILQ_NEXT(dip, list))
197: bios_diskinfo[i++] = dip->bios_info;
198:
199: bios_diskinfo[i++].bios_number = -1;
200: /* Register for kernel use */
201: addbootarg(BOOTARG_CKSUMLEN, sizeof(u_int32_t), &bios_cksumlen);
202: addbootarg(BOOTARG_DISKINFO, i * sizeof(bios_diskinfo_t), bios_diskinfo);
203: }
204:
205:
206: void
207: cdprobe(void)
208: {
209: struct diskinfo *dip;
210: int cddev = bios_cddev & 0xff;
211:
212: /* Another BIOS boot device... */
213:
214: if (bios_cddev == -1) /* Not been set, so don't use */
215: return;
216:
217: dip = alloc(sizeof(struct diskinfo));
218: bzero(dip, sizeof(*dip));
219:
220: #if 0
221: if (bios_getdiskinfo(cddev, &dip->bios_info)) {
222: printf(" <!cd0>"); /* XXX */
223: free(dip, 0);
224: return;
225: }
226: #endif
227:
228: printf(" cd0");
229:
230: dip->bios_info.bios_number = cddev;
231: dip->bios_info.bios_edd = 1; /* Use the LBA calls */
232: dip->bios_info.flags |= BDI_GOODLABEL | BDI_EL_TORITO;
233: dip->bios_info.checksum = 0; /* just in case */
234: dip->bios_info.bsd_dev =
235: MAKEBOOTDEV(0, 0, 0, 0xff, RAW_PART);
236:
237: /* Create an imaginary disk label */
238: dip->disklabel.d_secsize = 2048;
239: dip->disklabel.d_ntracks = 1;
240: dip->disklabel.d_nsectors = 100;
241: dip->disklabel.d_ncylinders = 1;
242: dip->disklabel.d_secpercyl = dip->disklabel.d_ntracks *
243: dip->disklabel.d_nsectors;
244: if (dip->disklabel.d_secpercyl == 0) {
245: dip->disklabel.d_secpercyl = 100;
246: /* as long as it's not 0, since readdisklabel divides by it */
247: }
248:
249: strncpy(dip->disklabel.d_typename, "ATAPI CD-ROM",
250: sizeof(dip->disklabel.d_typename));
251: dip->disklabel.d_type = DTYPE_ATAPI;
252:
253: strncpy(dip->disklabel.d_packname, "fictitious",
254: sizeof(dip->disklabel.d_packname));
255: dip->disklabel.d_secperunit = 100;
256: dip->disklabel.d_rpm = 300;
257: dip->disklabel.d_interleave = 1;
258:
259: dip->disklabel.d_bbsize = 2048;
260: dip->disklabel.d_sbsize = 2048;
261:
262: /* 'a' partition covering the "whole" disk */
263: dip->disklabel.d_partitions[0].p_offset = 0;
264: dip->disklabel.d_partitions[0].p_size = 100;
265: dip->disklabel.d_partitions[0].p_fstype = FS_UNUSED;
266:
267: /* The raw partition is special */
268: dip->disklabel.d_partitions[RAW_PART].p_offset = 0;
269: dip->disklabel.d_partitions[RAW_PART].p_size = 100;
270: dip->disklabel.d_partitions[RAW_PART].p_fstype = FS_UNUSED;
271:
272: dip->disklabel.d_npartitions = RAW_PART + 1;
273:
274: dip->disklabel.d_magic = DISKMAGIC;
275: dip->disklabel.d_magic2 = DISKMAGIC;
276: dip->disklabel.d_checksum = dkcksum(&dip->disklabel);
277:
278: /* Add to queue of disks */
279: TAILQ_INSERT_TAIL(&disklist, dip, list);
280: }
281:
282:
283: /* Find info on given BIOS disk */
284: struct diskinfo *
285: dklookup(int dev)
286: {
287: struct diskinfo *dip;
288:
289: for(dip = TAILQ_FIRST(&disklist); dip; dip = TAILQ_NEXT(dip, list))
290: if(dip->bios_info.bios_number == dev)
291: return(dip);
292:
293: return(NULL);
294: }
295:
296: void
297: dump_diskinfo(void)
298: {
299: struct diskinfo *dip;
300:
301: printf("Disk\tBIOS#\tType\tCyls\tHeads\tSecs\tFlags\tChecksum\n");
302: for (dip = TAILQ_FIRST(&disklist); dip; dip = TAILQ_NEXT(dip, list)) {
303: bios_diskinfo_t *bdi = &dip->bios_info;
304: int d = bdi->bios_number;
305: int u = d & 0x7f;
306: char c;
307:
308: if (bdi->flags & BDI_EL_TORITO) {
309: c = 'c';
310: u = 0;
311: } else {
312: c = (d & 0x80) ? 'h' : 'f';
313: }
314:
315: printf("%cd%d\t0x%x\t%s\t%d\t%d\t%d\t0x%x\t0x%x\n",
316: c, u, d,
317: (bdi->flags & BDI_BADLABEL)?"*none*":"label",
318: bdi->bios_cylinders, bdi->bios_heads, bdi->bios_sectors,
319: bdi->flags, bdi->checksum);
320: }
321: }
322:
323: /* Find BIOS portion on given BIOS disk
324: * XXX - Use dklookup() instead.
325: */
326: bios_diskinfo_t *
327: bios_dklookup(int dev)
328: {
329: struct diskinfo *dip;
330:
331: dip = dklookup(dev);
332: if(dip)
333: return(&dip->bios_info);
334:
335: return(NULL);
336: }
337:
338: /*
339: * Checksum one more block on all harddrives
340: *
341: * Use the adler32() function from libz,
342: * as it is quick, small, and available.
343: */
344: int
345: disksum(int blk)
346: {
347: struct diskinfo *dip, *dip2;
348: int st, reprobe = 0;
349: char *buf;
350:
351: buf = alloca(DEV_BSIZE);
352: for(dip = TAILQ_FIRST(&disklist); dip; dip = TAILQ_NEXT(dip, list)){
353: bios_diskinfo_t *bdi = &dip->bios_info;
354:
355: /* Skip this disk if it is not a HD or has had an I/O error */
356: if (!(bdi->bios_number & 0x80) || bdi->flags & BDI_INVALID)
357: continue;
358:
359: /* Adler32 checksum */
360: st = biosd_io(F_READ, bdi, blk, 1, buf);
361: if (st) {
362: bdi->flags |= BDI_INVALID;
363: continue;
364: }
365: bdi->checksum = adler32(bdi->checksum, buf, DEV_BSIZE);
366:
367: for(dip2 = TAILQ_FIRST(&disklist); dip2 != dip;
368: dip2 = TAILQ_NEXT(dip2, list)){
369: bios_diskinfo_t *bd = &dip2->bios_info;
370: if ((bd->bios_number & 0x80) &&
371: !(bd->flags & BDI_INVALID) &&
372: bdi->checksum == bd->checksum)
373: reprobe = 1;
374: }
375: }
376:
377: return (reprobe);
378: }
CVSweb