Annotation of sys/arch/i386/i386/dkcsum.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: dkcsum.c,v 1.21 2006/05/11 13:21:11 mickey Exp $ */
2:
3: /*-
4: * Copyright (c) 1997 Niklas Hallqvist. 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 ``AS IS'' AND ANY EXPRESS OR
16: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25: */
26:
27: /*
28: * A checksumming pseudo device used to get unique labels of each disk
29: * that needs to be matched to BIOS disks.
30: */
31:
32: #include <sys/param.h>
33: #include <sys/buf.h>
34: #include <sys/conf.h>
35: #include <sys/device.h>
36: #include <sys/disklabel.h>
37: #include <sys/fcntl.h>
38: #include <sys/proc.h>
39: #include <sys/reboot.h>
40: #include <sys/stat.h>
41: #include <sys/systm.h>
42:
43: #include <machine/biosvar.h>
44:
45: #include <lib/libz/zlib.h>
46:
47: dev_t dev_rawpart(struct device *); /* XXX */
48:
49: extern u_int32_t bios_cksumlen;
50: extern bios_diskinfo_t *bios_diskinfo;
51: extern dev_t bootdev;
52:
53: void
54: dkcsumattach(void)
55: {
56: struct device *dv;
57: struct buf *bp;
58: struct bdevsw *bdsw;
59: dev_t dev, pribootdev, altbootdev;
60: int error, picked;
61: u_int32_t csum;
62: bios_diskinfo_t *bdi, *hit;
63:
64: /* do nothing if no diskinfo passed from /boot, or a bad length */
65: if (bios_diskinfo == NULL || bios_cksumlen * DEV_BSIZE > MAXBSIZE)
66: return;
67:
68: #ifdef DEBUG
69: printf("dkcsum: bootdev=%#x\n", bootdev);
70: for (bdi = bios_diskinfo; bdi->bios_number != -1; bdi++)
71: if (bdi->bios_number & 0x80)
72: printf("dkcsum: BIOS drive %#x checksum is %#x\n",
73: bdi->bios_number, bdi->checksum);
74: #endif
75: pribootdev = altbootdev = 0;
76:
77: /*
78: * XXX What if DEV_BSIZE is changed to something else than the BIOS
79: * blocksize? Today, /boot doesn't cover that case so neither need
80: * I care here.
81: */
82: bp = geteblk(bios_cksumlen * DEV_BSIZE); /* XXX error check? */
83:
84: TAILQ_FOREACH(dv, &alldevs, dv_list) {
85: if (dv->dv_class != DV_DISK)
86: continue;
87: bp->b_dev = dev = dev_rawpart(dv);
88: if (dev == NODEV)
89: continue;
90: bdsw = &bdevsw[major(dev)];
91:
92: /*
93: * This open operation guarantees a proper initialization
94: * of the device, for future strategy calls.
95: */
96: error = (*bdsw->d_open)(dev, FREAD, S_IFCHR, curproc);
97: if (error) {
98: /* XXX What to do here? */
99: #ifdef DEBUG
100: printf("dkcsum: %s open failed (%d)\n",
101: dv->dv_xname, error);
102: #endif
103: continue;
104: }
105:
106: /* Read blocks to cksum. XXX maybe a d_read should be used. */
107: bp->b_blkno = 0;
108: bp->b_bcount = bios_cksumlen * DEV_BSIZE;
109: bp->b_flags = B_BUSY | B_READ;
110: bp->b_cylinder = 0;
111: (*bdsw->d_strategy)(bp);
112: if ((error = biowait(bp))) {
113: /* XXX What to do here? */
114: #ifdef DEBUG
115: printf("dkcsum: %s read failed (%d)\n",
116: dv->dv_xname, error);
117: #endif
118: error = (*bdsw->d_close)(dev, 0, S_IFCHR, curproc);
119: #ifdef DEBUG
120: if (error)
121: printf("dkcsum: %s close failed (%d)\n",
122: dv->dv_xname, error);
123: #endif
124: continue;
125: }
126: error = (*bdsw->d_close)(dev, FREAD, S_IFCHR, curproc);
127: if (error) {
128: /* XXX What to do here? */
129: #ifdef DEBUG
130: printf("dkcsum: %s closed failed (%d)\n",
131: dv->dv_xname, error);
132: #endif
133: continue;
134: }
135:
136: csum = adler32(0, bp->b_data, bios_cksumlen * DEV_BSIZE);
137: #ifdef DEBUG
138: printf("dkcsum: %s checksum is %#x\n", dv->dv_xname, csum);
139: #endif
140:
141: /* Find the BIOS device */
142: hit = 0;
143: for (bdi = bios_diskinfo; bdi->bios_number != -1; bdi++) {
144: /* Skip non-harddrives */
145: if (!(bdi->bios_number & 0x80))
146: continue;
147: if (bdi->checksum != csum)
148: continue;
149: picked = hit || (bdi->flags & BDI_PICKED);
150: if (!picked)
151: hit = bdi;
152: printf("dkcsum: %s matches BIOS drive %#x%s\n",
153: dv->dv_xname, bdi->bios_number,
154: (picked ? " IGNORED" : ""));
155: }
156:
157: /*
158: * If we have no hit, that's OK, we can see a lot more devices
159: * than the BIOS can, so this case is pretty normal.
160: */
161: if (!hit) {
162: #ifdef DEBUG
163: printf("dkcsum: %s has no matching BIOS drive\n",
164: dv->dv_xname);
165: #endif
166: continue;
167: }
168:
169: /*
170: * Fixup bootdev if units match. This means that all of
171: * hd*, sd*, wd*, will be interpreted the same. Not 100%
172: * backwards compatible, but sd* and wd* should be phased-
173: * out in the bootblocks.
174: */
175:
176: /* B_TYPE dependent hd unit counting bootblocks */
177: if ((B_TYPE(bootdev) == B_TYPE(hit->bsd_dev)) &&
178: (B_UNIT(bootdev) == B_UNIT(hit->bsd_dev))) {
179: int type, ctrl, adap, part, unit;
180:
181: type = major(bp->b_dev);
182: adap = B_ADAPTOR(bootdev);
183: ctrl = B_CONTROLLER(bootdev);
184: unit = DISKUNIT(bp->b_dev);
185: part = B_PARTITION(bootdev);
186:
187: pribootdev = MAKEBOOTDEV(type, ctrl, adap, unit, part);
188: #ifdef DEBUG
189: printf("dkcsum: %s is primary boot disk\n",
190: dv->dv_xname);
191: #endif
192: }
193: /* B_TYPE independent hd unit counting bootblocks */
194: if (B_UNIT(bootdev) == (hit->bios_number & 0x7F)) {
195: int type, ctrl, adap, part, unit;
196:
197: type = major(bp->b_dev);
198: adap = B_ADAPTOR(bootdev);
199: ctrl = B_CONTROLLER(bootdev);
200: unit = DISKUNIT(bp->b_dev);
201: part = B_PARTITION(bootdev);
202:
203: altbootdev = MAKEBOOTDEV(type, ctrl, adap, unit, part);
204: #ifdef DEBUG
205: printf("dkcsum: %s is alternate boot disk\n",
206: dv->dv_xname);
207: #endif
208: }
209:
210: /* This will overwrite /boot's guess, just so you remember */
211: hit->bsd_dev = MAKEBOOTDEV(major(bp->b_dev), 0, 0,
212: DISKUNIT(bp->b_dev), RAW_PART);
213: hit->flags |= BDI_PICKED;
214: }
215: bootdev = pribootdev ? pribootdev : altbootdev ? altbootdev : bootdev;
216:
217: bp->b_flags |= B_INVAL;
218: brelse(bp);
219: }
CVSweb