2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.1 (the "License"). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
22 * @APPLE_LICENSE_HEADER_END@
25 * Mach Operating System
26 * Copyright (c) 1990 Carnegie-Mellon University
27 * Copyright (c) 1989 Carnegie-Mellon University
28 * All rights reserved. The CMU software License Agreement specifies
29 * the terms and conditions for use and redistribution.
33 * INTEL CORPORATION PROPRIETARY INFORMATION
35 * This software is supplied under the terms of a license agreement or
36 * nondisclosure agreement with Intel Corporation and may not be copied
37 * nor disclosed except in accordance with the terms of that agreement.
39 * Copyright 1988, 1989 Intel Corporation
43 * Copyright 1993 NeXT Computer, Inc.
44 * All rights reserved.
47 #define DRIVER_PRIVATE
49 #include "sys/types.h"
50 #include "legacy/disk.h"
51 #include "legacy/fdisk.h"
56 * Type and constant definitions.
58 typedef struct disk_blk0 boot_sector
;
59 #define BOOT_SIGNATURE DISK_SIGNATURE
60 #define PART_TYPE_EXT 0x05
61 #define PART_TYPE_APPLE 0xa8
62 #define UFS_FRONT_PORCH 0
65 #define DPRINT(x) { printf x; }
66 #define DSPRINT(x) { printf x; sleep(1); }
73 * Function prototypes.
75 extern void spinActivityIndicator();
76 static void diskActivityHook();
77 static int Biosread(int biosdev
, int secno
);
78 static struct fdisk_part
* find_partition(u_int8_t type
,
85 #define SPT(di) ((di) & 0xff)
86 #define HEADS(di) ((((di)>>8) & 0xff) + 1)
87 #define SPC(di) (SPT(di) * HEADS(di))
88 #define BPS 512 /* sector size of the device */
89 #define N_CACHE_SECS (BIOS_LEN / BPS)
92 * Stores the geometry of the disk in order to
93 * perform LBA to CHS translation for non EBIOS calls.
95 static struct diskinfo
{
96 int spt
; /* sectors per track */
97 int spc
; /* sectors per cylinder */
103 int label_secsize
= BPS
;
105 daddr_t blknos
[NBUFS
];
106 struct iob iob
[NFILES
];
109 * intbuf points to the start of the sector cache. BIOS calls will
110 * store the sectors read into this memory area. If cache_valid
111 * is TRUE, then intbuf contents are valid. Otherwise, ignore the
112 * cache and read from disk.
114 * biosbuf points to a sector within the sector cache.
116 static char * const intbuf
= (char *)ptov(BIOS_ADDR
);
117 static BOOL cache_valid
= FALSE
;
118 static char * biosbuf
;
120 /*==========================================================================
124 devopen(char * name
, struct iob
* io
)
126 static int last_biosdev
= -1;
127 static daddr_t last_offset
= 0;
129 struct fdisk_part
* part
;
133 io
->dirbuf_blkno
= -1;
135 // Use cached values if possible.
137 if (io
->biosdev
== last_biosdev
) {
138 io
->i_boff
= last_offset
;
142 // initialize disk parameters -- spt and spc
143 // must do this before doing reads from the device.
145 di
= get_diskinfo(io
->biosdev
);
151 diskinfo
.spt
= SPT(di
);
152 diskinfo
.spc
= diskinfo
.spt
* HEADS(di
);
154 // FIXME - io->partition is ignored. Doesn't make sense anymore.
155 // we also don't overwrite the 'name' argument.
156 // Whats special about "$LBL" ?
158 part
= find_partition(PART_TYPE_APPLE
, io
->biosdev
, FALSE
);
161 DSPRINT(("Unable to find partition: IO error\n"));
163 last_offset
= io
->i_boff
= part
->relsect
+ UFS_FRONT_PORCH
/BPS
;
164 last_biosdev
= io
->biosdev
;
165 DSPRINT(("partition offset: %x\n", io
->i_boff
));
169 /*==========================================================================
174 cache_valid
= FALSE
; // invalidate the sector cache (intbuf)
177 /*==========================================================================
180 int devread(struct iob
* io
)
186 io
->i_flgs
|= F_RDDATA
;
188 io
->i_error
= 0; // assume the best
190 // dev = io->i_ino.i_dev;
192 sector
= io
->i_bn
* (label_secsize
/BPS
);
194 for (offset
= 0; offset
< io
->i_cc
; offset
+= BPS
) {
196 io
->i_error
= Biosread(io
->biosdev
, sector
);
200 /* copy 1 sector from the internal buffer biosbuf into buf */
201 bcopy(biosbuf
, &io
->i_ma
[offset
], BPS
);
206 io
->i_flgs
&= ~F_TYPEMASK
;
211 /*==========================================================================
212 * Maps (E)BIOS return codes to message strings.
214 struct bios_error_info
{
219 #define ECC_CORRECTED_ERR 0x11
221 static struct bios_error_info bios_errors
[] = {
222 {0x10, "Media error"},
223 {0x11, "Corrected ECC error"},
224 {0x20, "Controller or device error"},
225 {0x40, "Seek failed"},
226 {0x80, "Device timeout"},
227 {0xAA, "Drive not ready"},
232 bios_error(int errno
)
234 struct bios_error_info
* bp
;
236 for (bp
= bios_errors
; bp
->errno
; bp
++) {
237 if (bp
->errno
== errno
)
240 return "Error 0x%02x"; // No string, print error code only
243 /*==========================================================================
244 * Use BIOS INT13 calls to read the sector specified. This function will
245 * also perform read-ahead to cache a few subsequent sector to the sector
248 * The fields in diskinfo structure must be filled in before calling this
252 * Return code from INT13/F2 or INT13/F42 call. If operation was
253 * successful, 0 is returned.
257 Biosread(int biosdev
, int secno
)
259 static int xbiosdev
, xcyl
, xhead
, xsec
, xnsecs
;
261 extern unsigned char uses_ebios
[];
268 DSPRINT(("Biosread %d \n", secno
));
270 // To read the disk sectors, use EBIOS if we can. Otherwise,
271 // revert to the standard BIOS calls.
273 if ((biosdev
>= BIOS_DEV_HD
) && uses_ebios
[biosdev
- BIOS_DEV_HD
]) {
275 (biosdev
== xbiosdev
) &&
277 (secno
< (xsec
+ xnsecs
)))
279 biosbuf
= intbuf
+ (BPS
* (secno
- xsec
));
283 xnsecs
= N_CACHE_SECS
;
286 while ((rc
= ebiosread(biosdev
, secno
, xnsecs
)) && (++tries
< 5))
288 if (rc
== ECC_CORRECTED_ERR
) {
289 /* Ignore corrected ECC errors */
292 error(" EBIOS read error: %s\n", bios_error(rc
), rc
);
293 error(" Block %d Sectors %d\n", secno
, xnsecs
);
298 spt
= diskinfo
.spt
; // From previous INT13/F8 call.
302 head
= (secno
% spc
) / spt
;
306 (biosdev
== xbiosdev
) &&
310 (sec
< (xsec
+ xnsecs
)))
312 // this sector is in intbuf cache
313 biosbuf
= intbuf
+ (BPS
* (sec
- xsec
));
317 // Cache up to a track worth of sectors, but do not cross a
323 xnsecs
= ((sec
+ N_CACHE_SECS
) > spt
) ? (spt
- sec
) : N_CACHE_SECS
;
325 while ((rc
= biosread(biosdev
, cyl
, head
, sec
, xnsecs
)) &&
328 if (rc
== ECC_CORRECTED_ERR
) {
329 /* Ignore corrected ECC errors */
332 error(" BIOS read error: %s\n", bios_error(rc
), rc
);
333 error(" Block %d, Cyl %d Head %d Sector %d\n",
334 secno
, cyl
, head
, sec
);
339 // If the BIOS reported success, mark the sector cache as valid.
352 /*==========================================================================
353 * Replace this function if you want to change
354 * the way disk activity is indicated to the user.
357 diskActivityHook(void)
359 spinActivityIndicator();
362 /*==========================================================================
363 * Returns YES if the partition type specified is an extended fdisk
367 isExtendedPartition(u_int8_t type
)
371 u_int8_t extended_partitions
[] = {
373 0x0f, /* Win95 extended */
374 0x85, /* Linux extended */
378 i
< sizeof(extended_partitions
)/sizeof(extended_partitions
[0]);
381 if (extended_partitions
[i
] == type
)
387 /*==========================================================================
388 * Traverse the fdisk partition tables on disk until a partition is found
389 * that matches the specified type.
392 * type - Partition type to search for (e.g. 0xa7 for NeXTSTEP).
393 * biosdev - BIOS device unit. 0x80 and up for hard-drive.
394 * mba - If true, the partition found must be marked active.
397 * A pointer to the matching partition entry in biosbuf memory.
398 * Note that the starting LBA field in the partition entry is
399 * modified to contain the absolute sector address, rather than
400 * the relative address.
401 * A NULL is returned if a match is not found.
403 * There are certain fdisk rules that allows us to simplify the search.
405 * - There can be 0-1 extended partition entry in any partition table.
406 * - In the MBR, there can be 0-4 primary partitions entries.
407 * - In the extended partition, there can be 0-1 logical partition entry.
411 find_partition(u_int8_t type
, u_int8_t biosdev
, BOOL mba
)
413 #define MAX_ITERATIONS 128
415 static u_int32_t iter
= 0;
416 static u_int32_t offset_root
;
417 static u_int32_t offset
;
421 boot_sector
* bootsect
;
422 struct fdisk_part
* match
= 0;
423 struct fdisk_part
* parts
;
426 if (rc
= Biosread(biosdev
, 0)) // Read MBR at sector zero.
431 bootsect
= (boot_sector
*) biosbuf
;
432 if (bootsect
->signature
!= BOOT_SIGNATURE
)
435 // Find a primary or a logical partition that matches the partition
438 for (n
= 0, parts
= (struct fdisk_part
*) bootsect
->parts
;
442 DSPRINT(("fdisk: [%d] %02x\n", iter
, parts
->systid
));
444 if (mba
&& ((parts
->bootid
& 0x80) == 0))
447 if (parts
->systid
== type
) {
450 // Make the relsect field (LBA starting sector) absolute by
451 // adding in the offset.
453 parts
->relsect
+= offset
;
455 DSPRINT(("Found: %x (%d)\n", parts
->relsect
, parts
->numsect
));
461 // Find if there is an extended partition entry that points to
462 // an extended partition table. Note that we only allow up to
463 // one extended partition per partition table.
465 for (n
= 0, parts
= (struct fdisk_part
*) bootsect
->parts
;
469 DSPRINT(("fdisk: [E%d] %02x\n", iter
, parts
->systid
));
471 if (isExtendedPartition(parts
->systid
))
473 if (iter
> MAX_ITERATIONS
) // limit recursion depth
477 offset
= offset_root
= parts
->relsect
;
479 offset
= parts
->relsect
+ offset_root
;
483 // Load extended partition table.
485 if (((rc
= Biosread(biosdev
, offset
)) == 0) &&
486 (bootsect
->signature
== BOOT_SIGNATURE
))
488 match
= find_partition(type
, biosdev
, mba
);