Be paranoid about setting of %dl register for braindead BIOS's,
[unix-history] / sys / i386 / boot / disk.c
CommitLineData
15637ed4 1/*
15637ed4
RG
2 * Mach Operating System
3 * Copyright (c) 1992, 1991 Carnegie Mellon University
4 * All Rights Reserved.
5 *
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
11 *
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15 *
16 * Carnegie Mellon requests users of this software to return to
17 *
18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
19 * School of Computer Science
20 * Carnegie Mellon University
21 * Pittsburgh PA 15213-3890
22 *
23 * any improvements or extensions that they make and grant Carnegie Mellon
24 * the rights to redistribute these changes.
a27f4645 25 *
e4270b63 26 * from: Mach, Revision 2.2 92/04/04 11:35:49 rpd
091a0361
AC
27 * $Id: disk.c,v 1.4 1994/02/22 22:59:40 rgrimes Exp $
28 */
29
30/*
31 * 93/10/08 bde
32 * If there is no 386BSD partition, initialize the label sector with
33 * LABELSECTOR instead of with garbage.
34 *
35 * 93/08/22 bde
36 * Fixed reading of bad sector table. It is at the end of the 'c'
37 * partition, which is not always at the end of the disk.
15637ed4
RG
38 */
39
40#include "boot.h"
41#ifdef DO_BAD144
42#include <sys/dkbad.h>
43#endif DO_BAD144
44#include <sys/disklabel.h>
45
46#define BIOS_DEV_FLOPPY 0x0
47#define BIOS_DEV_WIN 0x80
48
49#define BPS 512
50#define SPT(di) ((di)&0xff)
51#define HEADS(di) ((((di)>>8)&0xff)+1)
52
53char *devs[] = {"wd", "hd", "fd", "wt", "sd", 0};
54
55#ifdef DO_BAD144
56struct dkbad dkb;
57int do_bad144;
58int bsize;
59#endif DO_BAD144
60
61int spt, spc;
62
63char *iodest;
64struct fs *fs;
65struct inode inode;
66int dosdev, unit, part, maj, boff, poff, bnum, cnt;
67
68/*#define EMBEDDED_DISKLABEL 1*/
69extern struct disklabel disklabel;
70/*struct disklabel disklabel;*/
71
72devopen()
73{
74 struct dos_partition *dptr;
75 struct disklabel *dl;
76 int dosdev = inode.i_dev;
77 int i, sector, di;
78
79 di = get_diskinfo(dosdev);
80 spc = (spt = SPT(di)) * HEADS(di);
81 if (dosdev == 2)
82 {
83 boff = 0;
84 part = (spt == 15 ? 3 : 1);
85 }
86 else
87 {
88#ifdef EMBEDDED_DISKLABEL
89 dl = &disklabel;
90#else EMBEDDED_DISKLABEL
91 Bread(dosdev, 0);
92 dptr = (struct dos_partition *)(((char *)0)+DOSPARTOFF);
091a0361 93 sector = LABELSECTOR;
15637ed4 94 for (i = 0; i < NDOSPART; i++, dptr++)
091a0361
AC
95 if (dptr->dp_typ == DOSPTYP_386BSD) {
96 sector = dptr->dp_start + LABELSECTOR;
15637ed4 97 break;
091a0361 98 }
15637ed4
RG
99 Bread(dosdev, sector++);
100 dl=((struct disklabel *)0);
101 disklabel = *dl; /* structure copy (maybe useful later)*/
102#endif EMBEDDED_DISKLABEL
103 if (dl->d_magic != DISKMAGIC) {
104 printf("bad disklabel");
105 return 1;
106 }
107 if( (maj == 4) || (maj == 0) || (maj == 1))
108 {
109 if (dl->d_type == DTYPE_SCSI)
110 {
111 maj = 4; /* use scsi as boot dev */
112 }
113 else
114 {
115 maj = 0; /* must be ESDI/IDE */
116 }
117 }
118 boff = dl->d_partitions[part].p_offset;
119#ifdef DO_BAD144
120 bsize = dl->d_partitions[part].p_size;
121 do_bad144 = 0;
122 if (dl->d_flags & D_BADSECT) {
123 /* this disk uses bad144 */
124 int i;
125 int dkbbnum;
126 struct dkbad *dkbptr;
127
091a0361
AC
128 /* find the first readable bad sector table */
129 /* some of this code is copied from ufs/ufs_disksubr.c */
130 /* including the bugs :-( */
15637ed4 131 /* read a bad sector table */
091a0361
AC
132
133#define BAD144_PART 2 /* XXX scattered magic numbers */
134#define BSD_PART 0 /* XXX should be 2 but bad144.c uses 0 */
135 if (dl->d_partitions[BSD_PART].p_offset != 0)
136 dkbbnum = dl->d_partitions[BAD144_PART].p_offset
137 + dl->d_partitions[BAD144_PART].p_size;
138 else
139 dkbbnum = dl->d_secperunit;
140 dkbbnum -= dl->d_nsectors;
141
15637ed4
RG
142 if (dl->d_secsize > DEV_BSIZE)
143 dkbbnum *= dl->d_secsize / DEV_BSIZE;
144 else
145 dkbbnum /= DEV_BSIZE / dl->d_secsize;
146 i = 0;
147 do_bad144 = 0;
148 do {
149 /* XXX: what if the "DOS sector" < 512 bytes ??? */
150 Bread(dosdev, dkbbnum + i);
151 dkbptr = (struct dkbad *) 0;
152/* XXX why is this not in <sys/dkbad.h> ??? */
153#define DKBAD_MAGIC 0x4321
154 if (dkbptr->bt_mbz == 0 &&
155 dkbptr->bt_flag == DKBAD_MAGIC) {
156 dkb = *dkbptr; /* structure copy */
157 do_bad144 = 1;
158 break;
159 }
160 i += 2;
161 } while (i < 10 && i < dl->d_nsectors);
162 if (!do_bad144)
091a0361 163 printf("Bad bad sector table\n");
15637ed4 164 else
091a0361 165 printf("Using bad sector table at %d\n", dkbbnum+i);
15637ed4
RG
166 }
167#endif DO_BAD144
168 }
169 return 0;
170}
171
172devread()
173{
174 int offset, sector = bnum;
175 int dosdev = inode.i_dev;
176 for (offset = 0; offset < cnt; offset += BPS)
177 {
178 Bread(dosdev, badsect(dosdev, sector++));
179 bcopy(0, iodest+offset, BPS);
180 }
181}
182
a27f4645
RM
183#define I_ADDR ((void *) 0) /* XXX where all reads go */
184
185/* Read ahead buffer large enough for one track on a 1440K floppy. For
186 * reading from floppies, the bootstrap has to be loaded on a 64K boundary
187 * to ensure that this buffer doesn't cross a 64K DMA boundary.
188 */
189#define RA_SECTORS 18
190static char ra_buf[RA_SECTORS * BPS];
2d95de23 191static int ra_dev;
a27f4645
RM
192static int ra_end;
193static int ra_first;
194
15637ed4
RG
195Bread(dosdev,sector)
196 int dosdev,sector;
197{
2d95de23 198 if (dosdev != ra_dev || sector < ra_first || sector >= ra_end)
15637ed4 199 {
a27f4645
RM
200 int cyl, head, sec, nsec;
201
202 cyl = sector/spc;
203 head = (sector % spc) / spt;
204 sec = sector % spt;
205 nsec = spt - sec;
206 if (nsec > RA_SECTORS)
207 nsec = RA_SECTORS;
208 twiddle();
209 if (biosread(dosdev, cyl, head, sec, nsec, ra_buf) != 0)
210 {
211 nsec = 1;
212 twiddle();
213 while (biosread(dosdev, cyl, head, sec, nsec, ra_buf) != 0) {
214 printf("Error: C:%d H:%d S:%d\n", cyl, head, sec);
215 twiddle();
216 }
217 }
2d95de23 218 ra_dev = dosdev;
a27f4645
RM
219 ra_first = sector;
220 ra_end = sector + nsec;
15637ed4 221 }
a27f4645 222 bcopy(ra_buf + (sector - ra_first) * BPS, I_ADDR, BPS);
15637ed4
RG
223}
224
225badsect(dosdev, sector)
226 int dosdev, sector;
227{
228 int i;
229#ifdef DO_BAD144
230 if (do_bad144) {
231 u_short cyl;
232 u_short head;
233 u_short sec;
234 int newsec;
235 struct disklabel *dl = &disklabel;
236
237 /* XXX */
238 /* from wd.c */
239 /* bt_cyl = cylinder number in sorted order */
240 /* bt_trksec is actually (head << 8) + sec */
241
242 /* only remap sectors in the partition */
243 if (sector < boff || sector >= boff + bsize) {
244 goto no_remap;
245 }
246
247 cyl = sector / dl->d_secpercyl;
248 head = (sector % dl->d_secpercyl) / dl->d_nsectors;
249 sec = sector % dl->d_nsectors;
250 sec = (head<<8) + sec;
251
252 /* now, look in the table for a possible bad sector */
253 for (i=0; i<126; i++) {
254 if (dkb.bt_bad[i].bt_cyl == cyl) {
255 /* found same cylinder */
256 if (dkb.bt_bad[i].bt_trksec == sec) {
257 /* FOUND! */
258 break;
259 }
260 } else if (dkb.bt_bad[i].bt_cyl > cyl) {
261 i = 126;
262 break;
263 }
264 }
265 if (i == 126) {
266 /* didn't find bad sector */
267 goto no_remap;
268 }
269 /* otherwise find replacement sector */
091a0361
AC
270 if (dl->d_partitions[BSD_PART].p_offset != 0)
271 newsec = dl->d_partitions[BAD144_PART].p_offset
272 + dl->d_partitions[BAD144_PART].p_size;
273 else
274 newsec = dl->d_secperunit;
275 newsec -= dl->d_nsectors + i + 1;
15637ed4
RG
276 return newsec;
277 }
278#endif DO_BAD144
279 no_remap:
280 return sector;
281}