]> git.saurik.com Git - apple/boot.git/blob - gen/libsaio/disk.c
41f0f3976aa640d0475774b822b14bf0baec4d84
[apple/boot.git] / gen / libsaio / disk.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 * Mach Operating System
27 * Copyright (c) 1990 Carnegie-Mellon University
28 * Copyright (c) 1989 Carnegie-Mellon University
29 * All rights reserved. The CMU software License Agreement specifies
30 * the terms and conditions for use and redistribution.
31 */
32
33 /*
34 * INTEL CORPORATION PROPRIETARY INFORMATION
35 *
36 * This software is supplied under the terms of a license agreement or
37 * nondisclosure agreement with Intel Corporation and may not be copied
38 * nor disclosed except in accordance with the terms of that agreement.
39 *
40 * Copyright 1988, 1989 Intel Corporation
41 */
42
43 /*
44 * Copyright 1993 NeXT Computer, Inc.
45 * All rights reserved.
46 */
47
48 #define DRIVER_PRIVATE
49
50 #import "sys/types.h"
51 #import <sys/disk.h>
52 #import <dev/i386/disk.h>
53 #import "libsaio.h"
54 #import "memory.h"
55
56 static Biosread(int biosdev, int secno);
57 static read_label(char *name, int biosdev, daddr_t *boff, int partition);
58 void diskActivityHook(void);
59 extern void spinActivityIndicator(void);
60
61 /* diskinfo unpacking */
62 #define SPT(di) ((di)&0xff)
63 #define HEADS(di) ((((di)>>8)&0xff)+1)
64 #define SPC(di) (SPT(di)*HEADS(di))
65 #define BPS 512 /* sector size of the device */
66 #define N_CACHE_SECS (BIOS_LEN / BPS)
67
68 #define DOS_BSIZE 512
69 #define DISKLABEL 15 /* sector num of disk label */
70
71 char *devsw[] = {
72 "sd",
73 "hd",
74 "fd",
75 NULL
76 };
77
78 struct diskinfo {
79 int spt; /* sectors per track */
80 int spc; /* sectors per cylinder */
81 } diskinfo;
82
83 char *b[NBUFS];
84 daddr_t blknos[NBUFS];
85 struct iob iob[NFILES];
86 int label_secsize;
87 static int label_cached;
88
89 // intbuf is the whole buffer, biosbuf is the current cached sector
90 static char * const intbuf = (char *)ptov(BIOS_ADDR);
91 char *biosbuf;
92
93 void
94 devopen(name, io)
95 char * name;
96 struct iob * io;
97 {
98 long di;
99
100 di = get_diskinfo(io->biosdev);
101
102 /* initialize disk parameters -- spt and spc */
103 io->i_error = 0;
104 io->dirbuf_blkno = -1;
105
106 diskinfo.spt = SPT(di);
107 diskinfo.spc = diskinfo.spt * HEADS(di);
108 if (read_label(name, io->biosdev, &io->i_boff, io->partition) < 0)
109 {
110 io->i_error = EIO;
111 }
112 }
113
114 void devflush()
115 {
116 Biosread(0,-1);
117 }
118
119
120 int devread(io)
121 struct iob *io;
122 {
123 long sector;
124 int offset;
125 int dev;
126
127 io->i_flgs |= F_RDDATA;
128
129 /* assume the best */
130 io->i_error = 0;
131
132 dev = io->i_ino.i_dev;
133
134 sector = io->i_bn * (label_secsize/DOS_BSIZE);
135
136 for (offset = 0; offset < io->i_cc; offset += BPS) {
137
138 io->i_error = Biosread(io->biosdev, sector);
139 if (io->i_error) {
140 return(-1);
141 }
142
143 /* copy 1 sector from the internal buffer biosbuf into buf */
144 bcopy(biosbuf, &io->i_ma[offset], BPS);
145
146 sector++;
147 }
148
149 io->i_flgs &= ~F_TYPEMASK;
150 return (io->i_cc);
151 }
152
153 /* A haque: Biosread(0,-1) means flush the sector cache.
154 */
155 static int
156 Biosread(int biosdev, int secno)
157 {
158 static int xbiosdev, xcyl=-1, xhead, xsec, xnsecs;
159
160 int rc;
161 int cyl, head, sec;
162 int spt, spc;
163 int tries = 0;
164
165 if (biosdev == 0 && secno == -1) {
166 xcyl = -1;
167 label_cached = 0;
168 return 0;
169 }
170 spt = diskinfo.spt;
171 spc = diskinfo.spc;
172
173 cyl = secno / spc;
174 head = (secno % spc) / spt;
175 sec = secno % spt;
176
177 if (biosdev == xbiosdev && cyl == xcyl && head == xhead &&
178 sec >= xsec && sec < (xsec + xnsecs))
179 { // this sector is in intbuf cache
180 biosbuf = intbuf + (BPS * (sec-xsec));
181 return 0;
182 }
183
184 xcyl = cyl;
185 label_cached = 1;
186 xhead = head;
187 xsec = sec;
188 xbiosdev = biosdev;
189 xnsecs = ((sec + N_CACHE_SECS) > spt) ? (spt - sec) : N_CACHE_SECS;
190 biosbuf = intbuf;
191
192 while ((rc = biosread(biosdev,cyl,head,sec, xnsecs)) && (++tries < 5))
193 {
194 #ifndef SMALL
195 error(" biosread error 0x%x @ %d, C:%d H:%d S:%d\n",
196 rc, secno, cyl, head, sec);
197 #endif
198 sleep(1); // on disk errors, bleh!
199 }
200 diskActivityHook();
201 return rc;
202 }
203
204 // extern char name[];
205
206 #ifndef SMALL
207 static int
208 read_label(
209 char *name,
210 int biosdev,
211 daddr_t *boff,
212 int partition
213 )
214 {
215 struct disk_label *dlp;
216 struct fdisk_part *fd;
217 struct disk_blk0 *blk0;
218 char *cp;
219 int n, rc;
220 int part_offset = 0;
221 static int cached_boff;
222
223 if (label_cached) {
224 *boff = cached_boff;
225 return 0;
226 }
227
228 // read sector 0 into the internal buffer "biosbuf"
229 if ( rc = Biosread(biosdev, 0) )
230 return -1;
231
232 // Check for a valid boot block.
233 blk0 = (struct disk_blk0 *)biosbuf;
234 if (blk0->signature == DISK_SIGNATURE) {
235 // Check to see if the disk has been partitioned with FDISK
236 // to allow DOS and ufs filesystems to exist on the same spindle.
237 fd = (struct fdisk_part *)blk0->parts;
238 for ( n = 0; n < FDISK_NPART; n++, fd++)
239 if (fd->systid == FDISK_NEXTNAME)
240 {
241 part_offset = fd->relsect;
242 break;
243 }
244 }
245 /* It's not an error if there is not a valid boot block. */
246
247 /* Read the NeXT disk label.
248 * Since we can't count on it fitting in the sector cache,
249 * we'll put it elsewhere.
250 */
251 dlp = (struct disk_label *)malloc(sizeof(*dlp) + BPS);
252 for(n = 0, cp = (char *)dlp;
253 n < ((sizeof(*dlp) + BPS - 1) / BPS);
254 n++, cp += BPS) {
255 if (rc = Biosread(biosdev, DISKLABEL + part_offset + n))
256 goto error;
257 bcopy(biosbuf, cp, BPS);
258 }
259
260 byte_swap_disklabel_in(dlp);
261
262 /* Check label */
263
264 if (dlp->dl_version != DL_V3) {
265 error("bad disk label magic\n");
266 goto error;
267 }
268
269 label_secsize = dlp->dl_secsize;
270
271 if ((dlp->dl_part[partition].p_base) < 0) {
272 error("no such partition\n");
273 goto error;
274 }
275
276 *boff = cached_boff = dlp->dl_front + dlp->dl_part[partition].p_base;
277
278 if (!strcmp(name,"$LBL")) strcpy(name, dlp->dl_bootfile);
279
280 free((char *)dlp);
281 return 0;
282 error:
283 free((char *)dlp);
284 return -1;
285 }
286
287 #endif SMALL
288
289
290 /* replace this function if you want to change
291 * the way disk activity is indicated to the user.
292 */
293
294 void
295 diskActivityHook(void)
296 {
297 spinActivityIndicator();
298 }
299
300
301