15a69bb27SFrançois Revol/*
234dc9962SFrançois Revol * Copyright 2008-2010, Fran��ois Revol, revol@free.fr. All rights reserved.
35a69bb27SFrançois Revol * Copyright 2003-2006, Axel D��rfler, axeld@pinc-software.de.
45a69bb27SFrançois Revol * Distributed under the terms of the MIT License.
55a69bb27SFrançois Revol */
65a69bb27SFrançois Revol
75a69bb27SFrançois Revol
85a69bb27SFrançois Revol#include <KernelExport.h>
95a69bb27SFrançois Revol#include <boot/platform.h>
105a69bb27SFrançois Revol#include <boot/partitions.h>
115a69bb27SFrançois Revol#include <boot/stdio.h>
125a69bb27SFrançois Revol#include <boot/stage2.h>
135a69bb27SFrançois Revol
145a69bb27SFrançois Revol#include <string.h>
155a69bb27SFrançois Revol
1689ae49c7SFrançois Revol#include "Handle.h"
1741eebe05SFrançois Revol#include "toscalls.h"
1841eebe05SFrançois Revol
1912442ce5SFrançois Revol//#define TRACE_DEVICES
205a69bb27SFrançois Revol#ifdef TRACE_DEVICES
215a69bb27SFrançois Revol#	define TRACE(x) dprintf x
225a69bb27SFrançois Revol#else
235a69bb27SFrançois Revol#	define TRACE(x) ;
245a69bb27SFrançois Revol#endif
255a69bb27SFrançois Revol
265a69bb27SFrançois Revol
275a69bb27SFrançois Revol// exported from shell.S
285a69bb27SFrançois Revolextern uint8 gBootedFromImage;
2912442ce5SFrançois Revolextern uint8 gBootDriveAPI; // ATARI_BOOT_DRIVE_API_*
305a69bb27SFrançois Revolextern uint8 gBootDriveID;
315a69bb27SFrançois Revolextern uint32 gBootPartitionOffset;
325a69bb27SFrançois Revol
335a69bb27SFrançois Revol#define SCRATCH_SIZE (2*4096)
343ef0397bSFrançois Revolstatic uint8 gScratchBuffer[SCRATCH_SIZE];
355a69bb27SFrançois Revol
36d4d03238SFrançois Revolstatic const uint16 kParametersSizeVersion1 = sizeof(struct tos_bpb);
375a69bb27SFrançois Revolstatic const uint16 kParametersSizeVersion2 = 0x1e;
385a69bb27SFrançois Revolstatic const uint16 kParametersSizeVersion3 = 0x42;
395a69bb27SFrançois Revol
405a69bb27SFrançois Revolstatic const uint16 kDevicePathSignature = 0xbedd;
415a69bb27SFrançois Revol
421906acb2SFrançois Revol//XXX clean this up!
435a69bb27SFrançois Revolstruct drive_parameters {
44d4d03238SFrançois Revol	struct tos_bpb bpb;
455a69bb27SFrançois Revol	uint16		parameters_size;
465a69bb27SFrançois Revol	uint16		flags;
475a69bb27SFrançois Revol	uint32		cylinders;
485a69bb27SFrançois Revol	uint32		heads;
495a69bb27SFrançois Revol	uint32		sectors_per_track;
505a69bb27SFrançois Revol	uint64		sectors;
515a69bb27SFrançois Revol	uint16		bytes_per_sector;
525a69bb27SFrançois Revol	/* edd 2.0 */
531906acb2SFrançois Revol	//real_addr	device_table;
545a69bb27SFrançois Revol	/* edd 3.0 */
555a69bb27SFrançois Revol	uint16		device_path_signature;
565a69bb27SFrançois Revol	uint8		device_path_size;
575a69bb27SFrançois Revol	uint8		reserved1[3];
585a69bb27SFrançois Revol	char		host_bus[4];
595a69bb27SFrançois Revol	char		interface_type[8];
605a69bb27SFrançois Revol	union {
615a69bb27SFrançois Revol		struct {
625a69bb27SFrançois Revol			uint16	base_address;
635a69bb27SFrançois Revol		} legacy;
645a69bb27SFrançois Revol		struct {
655a69bb27SFrançois Revol			uint8	bus;
665a69bb27SFrançois Revol			uint8	slot;
675a69bb27SFrançois Revol			uint8	function;
685a69bb27SFrançois Revol		} pci;
695a69bb27SFrançois Revol		uint8		reserved[8];
705a69bb27SFrançois Revol	} interface;
715a69bb27SFrançois Revol	union {
725a69bb27SFrançois Revol		struct {
735a69bb27SFrançois Revol			uint8	slave;
745a69bb27SFrançois Revol		} ata;
755a69bb27SFrançois Revol		struct {
765a69bb27SFrançois Revol			uint8	slave;
775a69bb27SFrançois Revol			uint8	logical_unit;
785a69bb27SFrançois Revol		} atapi;
795a69bb27SFrançois Revol		struct {
805a69bb27SFrançois Revol			uint8	logical_unit;
815a69bb27SFrançois Revol		} scsi;
825a69bb27SFrançois Revol		struct {
835a69bb27SFrançois Revol			uint8	tbd;
845a69bb27SFrançois Revol		} usb;
855a69bb27SFrançois Revol		struct {
865a69bb27SFrançois Revol			uint64	guid;
875a69bb27SFrançois Revol		} firewire;
885a69bb27SFrançois Revol		struct {
895a69bb27SFrançois Revol			uint64	wwd;
905a69bb27SFrançois Revol		} fibre;
915a69bb27SFrançois Revol	} device;
925a69bb27SFrançois Revol	uint8		reserved2;
935a69bb27SFrançois Revol	uint8		checksum;
945a69bb27SFrançois Revol} _PACKED;
955a69bb27SFrançois Revol
965a69bb27SFrançois Revolstruct device_table {
975a69bb27SFrançois Revol	uint16	base_address;
985a69bb27SFrançois Revol	uint16	control_port_address;
995a69bb27SFrançois Revol	uint8	_reserved1 : 4;
1005a69bb27SFrançois Revol	uint8	is_slave : 1;
1015a69bb27SFrançois Revol	uint8	_reserved2 : 1;
1025a69bb27SFrançois Revol	uint8	lba_enabled : 1;
1035a69bb27SFrançois Revol} _PACKED;
1045a69bb27SFrançois Revol
1055a69bb27SFrançois Revolstruct specification_packet {
1065a69bb27SFrançois Revol	uint8	size;
1075a69bb27SFrançois Revol	uint8	media_type;
1085a69bb27SFrançois Revol	uint8	drive_number;
1095a69bb27SFrançois Revol	uint8	controller_index;
1105a69bb27SFrançois Revol	uint32	start_emulation;
1115a69bb27SFrançois Revol	uint16	device_specification;
1125a69bb27SFrançois Revol	uint8	_more_[9];
1135a69bb27SFrançois Revol} _PACKED;
1145a69bb27SFrançois Revol
1155a69bb27SFrançois Revolclass BlockHandle : public Handle {
1165a69bb27SFrançois Revol	public:
1175a69bb27SFrançois Revol		BlockHandle(int handle);
1185a69bb27SFrançois Revol		virtual ~BlockHandle();
1195a69bb27SFrançois Revol
1205a69bb27SFrançois Revol		virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize);
1215a69bb27SFrançois Revol		virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize);
1225a69bb27SFrançois Revol
123d4d03238SFrançois Revol		virtual off_t Size() const { return fSize; };
1245a69bb27SFrançois Revol
1255a69bb27SFrançois Revol		uint32 BlockSize() const { return fBlockSize; }
1265a69bb27SFrançois Revol
1275a69bb27SFrançois Revol		bool HasParameters() const { return fHasParameters; }
1285a69bb27SFrançois Revol		const drive_parameters &Parameters() const { return fParameters; }
1295a69bb27SFrançois Revol
130588b2cd4SFrançois Revol		virtual status_t FillIdentifier();
131588b2cd4SFrançois Revol
1325a69bb27SFrançois Revol		disk_identifier &Identifier() { return fIdentifier; }
1335a69bb27SFrançois Revol		uint8 DriveID() const { return fHandle; }
134588b2cd4SFrançois Revol		status_t InitCheck() const { return fSize > 0 ? B_OK : B_ERROR; };
135588b2cd4SFrançois Revol
136588b2cd4SFrançois Revol
137d4d03238SFrançois Revol
138d4d03238SFrançois Revol		virtual ssize_t ReadBlocks(void *buffer, off_t first, int32 count);
1395a69bb27SFrançois Revol
1405a69bb27SFrançois Revol	protected:
1415a69bb27SFrançois Revol		uint64	fSize;
1425a69bb27SFrançois Revol		uint32	fBlockSize;
1435a69bb27SFrançois Revol		bool	fHasParameters;
1445a69bb27SFrançois Revol		drive_parameters fParameters;
1455a69bb27SFrançois Revol		disk_identifier fIdentifier;
1465a69bb27SFrançois Revol};
1475a69bb27SFrançois Revol
1485a69bb27SFrançois Revol
149f77b0a6bSFrançois Revolclass FloppyDrive : public BlockHandle {
150f77b0a6bSFrançois Revol	public:
151f77b0a6bSFrançois Revol		FloppyDrive(int handle);
152f77b0a6bSFrançois Revol		virtual ~FloppyDrive();
153f77b0a6bSFrançois Revol
154f77b0a6bSFrançois Revol		status_t FillIdentifier();
155f77b0a6bSFrançois Revol
156f77b0a6bSFrançois Revol		virtual ssize_t ReadBlocks(void *buffer, off_t first, int32 count);
157f77b0a6bSFrançois Revol
158f77b0a6bSFrançois Revol	protected:
159f77b0a6bSFrançois Revol		status_t	ReadBPB(struct tos_bpb *bpb);
160f77b0a6bSFrançois Revol};
161f77b0a6bSFrançois Revol
162f77b0a6bSFrançois Revol
163d4d03238SFrançois Revolclass BIOSDrive : public BlockHandle {
164d4d03238SFrançois Revol	public:
165d4d03238SFrançois Revol		BIOSDrive(int handle);
166d4d03238SFrançois Revol		virtual ~BIOSDrive();
167d4d03238SFrançois Revol
168d4d03238SFrançois Revol		status_t FillIdentifier();
169d4d03238SFrançois Revol
170d4d03238SFrançois Revol		virtual ssize_t ReadBlocks(void *buffer, off_t first, int32 count);
171d4d03238SFrançois Revol
172d4d03238SFrançois Revol	protected:
173d4d03238SFrançois Revol		status_t	ReadBPB(struct tos_bpb *bpb);
174d4d03238SFrançois Revol};
175d4d03238SFrançois Revol
176d4d03238SFrançois Revol
177d4d03238SFrançois Revolclass XHDIDrive : public BlockHandle {
178d4d03238SFrançois Revol	public:
179b516effeSFrançois Revol		XHDIDrive(int handle, uint16 major, uint16 minor);
180d4d03238SFrançois Revol		virtual ~XHDIDrive();
181d4d03238SFrançois Revol
182d4d03238SFrançois Revol		status_t FillIdentifier();
183d4d03238SFrançois Revol
184d4d03238SFrançois Revol		virtual ssize_t ReadBlocks(void *buffer, off_t first, int32 count);
185d4d03238SFrançois Revol
186d4d03238SFrançois Revol	protected:
187d4d03238SFrançois Revol		uint16 fMajor;
188d4d03238SFrançois Revol		uint16 fMinor;
189d4d03238SFrançois Revol};
190d4d03238SFrançois Revol
191d4d03238SFrançois Revol
1925a69bb27SFrançois Revolstatic bool sBlockDevicesAdded = false;
1935a69bb27SFrançois Revol
1945a69bb27SFrançois Revol
19589ae49c7SFrançois Revolstatic status_t
196d4d03238SFrançois Revolread_bpb(uint8 drive, struct tos_bpb *bpb)
19789ae49c7SFrançois Revol{
198d4d03238SFrançois Revol	struct tos_bpb *p;
19989ae49c7SFrançois Revol	p = Getbpb(drive);
200d4d03238SFrançois Revol	memcpy(bpb, p, sizeof(struct tos_bpb));
20189ae49c7SFrançois Revol	/* Getbpb is buggy so we must force a media change */
20289ae49c7SFrançois Revol	//XXX: docs seems to assume we should loop until it works
20389ae49c7SFrançois Revol	Mediach(drive);
20489ae49c7SFrançois Revol	return B_OK;
20589ae49c7SFrançois Revol}
20689ae49c7SFrançois Revol
2075a69bb27SFrançois Revolstatic status_t
2085a69bb27SFrançois Revolget_drive_parameters(uint8 drive, drive_parameters *parameters)
2095a69bb27SFrançois Revol{
21089ae49c7SFrançois Revol	status_t err;
21189ae49c7SFrançois Revol	err = read_bpb(drive, &parameters->bpb);
212f77b0a6bSFrançois Revol	TRACE(("get_drive_parameters: get_bpb: 0x%08lx\n", err));
213f77b0a6bSFrançois Revol	TRACE(("get_drive_parameters: bpb: %04x %04x %04x %04x %04x %04x %04x %04x %04x \n",
214f77b0a6bSFrançois Revol			parameters->bpb.recsiz, parameters->bpb.clsiz,
215f77b0a6bSFrançois Revol			parameters->bpb.clsizb, parameters->bpb.rdlen,
216f77b0a6bSFrançois Revol			parameters->bpb.fsiz, parameters->bpb.fatrec,
217f77b0a6bSFrançois Revol			parameters->bpb.datrec, parameters->bpb.numcl,
218f77b0a6bSFrançois Revol			parameters->bpb.bflags));
219f77b0a6bSFrançois Revol
22089ae49c7SFrançois Revol#if 0
2215a69bb27SFrançois Revol	// fill drive_parameters structure with useful values
2225a69bb27SFrançois Revol	parameters->parameters_size = kParametersSizeVersion1;
2235a69bb27SFrançois Revol	parameters->flags = 0;
2245a69bb27SFrançois Revol	parameters->cylinders = (((regs.ecx & 0xc0) << 2) | ((regs.ecx >> 8) & 0xff)) + 1;
2255a69bb27SFrançois Revol	parameters->heads = ((regs.edx >> 8) & 0xff) + 1;
2265a69bb27SFrançois Revol		// heads and cylinders start counting from 0
2275a69bb27SFrançois Revol	parameters->sectors_per_track = regs.ecx & 0x3f;
2285a69bb27SFrançois Revol	parameters->sectors = parameters->cylinders * parameters->heads
2295a69bb27SFrançois Revol		* parameters->sectors_per_track;
2305a69bb27SFrançois Revol	parameters->bytes_per_sector = 512;
23189ae49c7SFrançois Revol#endif
2325a69bb27SFrançois Revol	return B_OK;
2335a69bb27SFrançois Revol}
2345a69bb27SFrançois Revol
2355a69bb27SFrançois Revol
23689ae49c7SFrançois Revol#if 0
2375a69bb27SFrançois Revol/** parse EDD 3.0 drive path information */
2385a69bb27SFrançois Revol
2395a69bb27SFrançois Revolstatic status_t
2405a69bb27SFrançois Revolfill_disk_identifier_v3(disk_identifier &disk, const drive_parameters &parameters)
2415a69bb27SFrançois Revol{
2425a69bb27SFrançois Revol	if (parameters.parameters_size < kParametersSizeVersion3
2435a69bb27SFrançois Revol		|| parameters.device_path_signature != kDevicePathSignature)
2445a69bb27SFrançois Revol		return B_BAD_TYPE;
2455a69bb27SFrançois Revol
2465a69bb27SFrançois Revol	// parse host bus
2475a69bb27SFrançois Revol
2485a69bb27SFrançois Revol	if (!strncmp(parameters.host_bus, "PCI", 3)) {
2495a69bb27SFrançois Revol		disk.bus_type = PCI_BUS;
2505a69bb27SFrançois Revol
2515a69bb27SFrançois Revol		disk.bus.pci.bus = parameters.interface.pci.bus;
2525a69bb27SFrançois Revol		disk.bus.pci.slot = parameters.interface.pci.slot;
2535a69bb27SFrançois Revol		disk.bus.pci.function = parameters.interface.pci.function;
2545a69bb27SFrançois Revol	} else if (!strncmp(parameters.host_bus, "ISA", 3)) {
2555a69bb27SFrançois Revol		disk.bus_type = LEGACY_BUS;
2565a69bb27SFrançois Revol
2575a69bb27SFrançois Revol		disk.bus.legacy.base_address = parameters.interface.legacy.base_address;
2585a69bb27SFrançois Revol		dprintf("legacy base address %x\n", disk.bus.legacy.base_address);
2595a69bb27SFrançois Revol	} else {
2605a69bb27SFrançois Revol		dprintf("unknown host bus \"%s\"\n", parameters.host_bus);
2615a69bb27SFrançois Revol		return B_BAD_DATA;
2625a69bb27SFrançois Revol	}
2635a69bb27SFrançois Revol
2645a69bb27SFrançois Revol	// parse interface
2655a69bb27SFrançois Revol
2665a69bb27SFrançois Revol	if (!strncmp(parameters.interface_type, "ATA", 3)) {
2675a69bb27SFrançois Revol		disk.device_type = ATA_DEVICE;
2685a69bb27SFrançois Revol		disk.device.ata.master = !parameters.device.ata.slave;
2695a69bb27SFrançois Revol		dprintf("ATA device, %s\n", disk.device.ata.master ? "master" : "slave");
2705a69bb27SFrançois Revol	} else if (!strncmp(parameters.interface_type, "ATAPI", 3)) {
2715a69bb27SFrançois Revol		disk.device_type = ATAPI_DEVICE;
2725a69bb27SFrançois Revol		disk.device.atapi.master = !parameters.device.ata.slave;
2735a69bb27SFrançois Revol		disk.device.atapi.logical_unit = parameters.device.atapi.logical_unit;
2745a69bb27SFrançois Revol	} else if (!strncmp(parameters.interface_type, "SCSI", 3)) {
2755a69bb27SFrançois Revol		disk.device_type = SCSI_DEVICE;
2765a69bb27SFrançois Revol		disk.device.scsi.logical_unit = parameters.device.scsi.logical_unit;
2775a69bb27SFrançois Revol	} else if (!strncmp(parameters.interface_type, "USB", 3)) {
2785a69bb27SFrançois Revol		disk.device_type = USB_DEVICE;
2795a69bb27SFrançois Revol		disk.device.usb.tbd = parameters.device.usb.tbd;
2805a69bb27SFrançois Revol	} else if (!strncmp(parameters.interface_type, "1394", 3)) {
2815a69bb27SFrançois Revol		disk.device_type = FIREWIRE_DEVICE;
2825a69bb27SFrançois Revol		disk.device.firewire.guid = parameters.device.firewire.guid;
2835a69bb27SFrançois Revol	} else if (!strncmp(parameters.interface_type, "FIBRE", 3)) {
2845a69bb27SFrançois Revol		disk.device_type = FIBRE_DEVICE;
2855a69bb27SFrançois Revol		disk.device.fibre.wwd = parameters.device.fibre.wwd;
2865a69bb27SFrançois Revol	} else {
2875a69bb27SFrançois Revol		dprintf("unknown interface type \"%s\"\n", parameters.interface_type);
2885a69bb27SFrançois Revol		return B_BAD_DATA;
2895a69bb27SFrançois Revol	}
2905a69bb27SFrançois Revol
2915a69bb27SFrançois Revol	return B_OK;
2925a69bb27SFrançois Revol}
2935a69bb27SFrançois Revol
2945a69bb27SFrançois Revol
2955a69bb27SFrançois Revol/** EDD 2.0 drive table information */
2965a69bb27SFrançois Revol
2975a69bb27SFrançois Revolstatic status_t
2985a69bb27SFrançois Revolfill_disk_identifier_v2(disk_identifier &disk, const drive_parameters &parameters)
2995a69bb27SFrançois Revol{
3005a69bb27SFrançois Revol	if (parameters.device_table.segment == 0xffff
3015a69bb27SFrançois Revol		&& parameters.device_table.offset == 0xffff)
3025a69bb27SFrançois Revol		return B_BAD_TYPE;
3035a69bb27SFrançois Revol
3045a69bb27SFrançois Revol	device_table *table = (device_table *)LINEAR_ADDRESS(parameters.device_table.segment,
3055a69bb27SFrançois Revol		parameters.device_table.offset);
3065a69bb27SFrançois Revol
3075a69bb27SFrançois Revol	disk.bus_type = LEGACY_BUS;
3085a69bb27SFrançois Revol	disk.bus.legacy.base_address = table->base_address;
3095a69bb27SFrançois Revol
3105a69bb27SFrançois Revol	disk.device_type = ATA_DEVICE;
3115a69bb27SFrançois Revol	disk.device.ata.master = !table->is_slave;
3125a69bb27SFrançois Revol
3135a69bb27SFrançois Revol	return B_OK;
3145a69bb27SFrançois Revol}
31589ae49c7SFrançois Revol#endif
3165a69bb27SFrançois Revol
3175a69bb27SFrançois Revolstatic off_t
3185a69bb27SFrançois Revolget_next_check_sum_offset(int32 index, off_t maxSize)
3195a69bb27SFrançois Revol{
32046cf7a5aSPrzemysław Buczkowski	// The boot block often contains the disk superblock, and should be
3215a69bb27SFrançois Revol	// unique enough for most cases
3225a69bb27SFrançois Revol	if (index < 2)
3235a69bb27SFrançois Revol		return index * 512;
3245a69bb27SFrançois Revol
3255a69bb27SFrançois Revol	// Try some data in the first part of the drive
3265a69bb27SFrançois Revol	if (index < 4)
3275a69bb27SFrançois Revol		return (maxSize >> 10) + index * 2048;
3285a69bb27SFrançois Revol
3295a69bb27SFrançois Revol	// Some random value might do
3305a69bb27SFrançois Revol	return ((system_time() + index) % (maxSize >> 9)) * 512;
3315a69bb27SFrançois Revol}
3325a69bb27SFrançois Revol
3335a69bb27SFrançois Revol
3345a69bb27SFrançois Revol/**	Computes a check sum for the specified block.
3355a69bb27SFrançois Revol *	The check sum is the sum of all data in that block interpreted as an
3365a69bb27SFrançois Revol *	array of uint32 values.
3375a69bb27SFrançois Revol *	Note, this must use the same method as the one used in kernel/fs/vfs_boot.cpp.
3385a69bb27SFrançois Revol */
3395a69bb27SFrançois Revol
3405a69bb27SFrançois Revolstatic uint32
3415a69bb27SFrançois Revolcompute_check_sum(BlockHandle *drive, off_t offset)
3425a69bb27SFrançois Revol{
3435a69bb27SFrançois Revol	char buffer[512];
3445a69bb27SFrançois Revol	ssize_t bytesRead = drive->ReadAt(NULL, offset, buffer, sizeof(buffer));
3455a69bb27SFrançois Revol	if (bytesRead < B_OK)
3465a69bb27SFrançois Revol		return 0;
3475a69bb27SFrançois Revol
3485a69bb27SFrançois Revol	if (bytesRead < (ssize_t)sizeof(buffer))
3495a69bb27SFrançois Revol		memset(buffer + bytesRead, 0, sizeof(buffer) - bytesRead);
3505a69bb27SFrançois Revol
3515a69bb27SFrançois Revol	uint32 *array = (uint32 *)buffer;
3525a69bb27SFrançois Revol	uint32 sum = 0;
3535a69bb27SFrançois Revol
3545a69bb27SFrançois Revol	for (uint32 i = 0; i < (bytesRead + sizeof(uint32) - 1) / sizeof(uint32); i++) {
3555a69bb27SFrançois Revol		sum += array[i];
3565a69bb27SFrançois Revol	}
3575a69bb27SFrançois Revol
3585a69bb27SFrançois Revol	return sum;
3595a69bb27SFrançois Revol}
3605a69bb27SFrançois Revol
3615a69bb27SFrançois Revol
3625a69bb27SFrançois Revolstatic void
3635a69bb27SFrançois Revolfind_unique_check_sums(NodeList *devices)
3645a69bb27SFrançois Revol{
3655a69bb27SFrançois Revol	NodeIterator iterator = devices->GetIterator();
3665a69bb27SFrançois Revol	Node *device;
3675a69bb27SFrançois Revol	int32 index = 0;
3685a69bb27SFrançois Revol	off_t minSize = 0;
3695a69bb27SFrançois Revol	const int32 kMaxTries = 200;
3705a69bb27SFrançois Revol
3715a69bb27SFrançois Revol	while (index < kMaxTries) {
3725a69bb27SFrançois Revol		bool clash = false;
3735a69bb27SFrançois Revol
3745a69bb27SFrançois Revol		iterator.Rewind();
3755a69bb27SFrançois Revol
3765a69bb27SFrançois Revol		while ((device = iterator.Next()) != NULL) {
3775a69bb27SFrançois Revol			BlockHandle *drive = (BlockHandle *)device;
3785a69bb27SFrançois Revol#if 0
3795a69bb27SFrançois Revol			// there is no RTTI in the boot loader...
3805a69bb27SFrançois Revol			BlockHandle *drive = dynamic_cast<BlockHandle *>(device);
3815a69bb27SFrançois Revol			if (drive == NULL)
3825a69bb27SFrançois Revol				continue;
3835a69bb27SFrançois Revol#endif
3845a69bb27SFrançois Revol
3855a69bb27SFrançois Revol			// TODO: currently, we assume that the BIOS provided us with unique
3865a69bb27SFrançois Revol			//	disk identifiers... hopefully this is a good idea
3875a69bb27SFrançois Revol			if (drive->Identifier().device_type != UNKNOWN_DEVICE)
3885a69bb27SFrançois Revol				continue;
3895a69bb27SFrançois Revol
3905a69bb27SFrançois Revol			if (minSize == 0 || drive->Size() < minSize)
3915a69bb27SFrançois Revol				minSize = drive->Size();
3925a69bb27SFrançois Revol
3935a69bb27SFrançois Revol			// check for clashes
3945a69bb27SFrançois Revol
3955a69bb27SFrançois Revol			NodeIterator compareIterator = devices->GetIterator();
3965a69bb27SFrançois Revol			while ((device = compareIterator.Next()) != NULL) {
3975a69bb27SFrançois Revol				BlockHandle *compareDrive = (BlockHandle *)device;
3985a69bb27SFrançois Revol
3995a69bb27SFrançois Revol				if (compareDrive == drive
4005a69bb27SFrançois Revol					|| compareDrive->Identifier().device_type != UNKNOWN_DEVICE)
4015a69bb27SFrançois Revol					continue;
4025a69bb27SFrançois Revol
4035a69bb27SFrançois Revol				if (!memcmp(&drive->Identifier(), &compareDrive->Identifier(),
4045a69bb27SFrançois Revol						sizeof(disk_identifier))) {
4055a69bb27SFrançois Revol					clash = true;
4065a69bb27SFrançois Revol					break;
4075a69bb27SFrançois Revol				}
4085a69bb27SFrançois Revol			}
4095a69bb27SFrançois Revol
4105a69bb27SFrançois Revol			if (clash)
4115a69bb27SFrançois Revol				break;
4125a69bb27SFrançois Revol		}
4135a69bb27SFrançois Revol
4145a69bb27SFrançois Revol		if (!clash) {
4155a69bb27SFrançois Revol			// our work here is done.
4165a69bb27SFrançois Revol			return;
4175a69bb27SFrançois Revol		}
4185a69bb27SFrançois Revol
4195a69bb27SFrançois Revol		// add a new block to the check sums
4205a69bb27SFrançois Revol
4215a69bb27SFrançois Revol		off_t offset = get_next_check_sum_offset(index, minSize);
4225a69bb27SFrançois Revol		int32 i = index % NUM_DISK_CHECK_SUMS;
4235a69bb27SFrançois Revol		iterator.Rewind();
4245a69bb27SFrançois Revol
4255a69bb27SFrançois Revol		while ((device = iterator.Next()) != NULL) {
4265a69bb27SFrançois Revol			BlockHandle *drive = (BlockHandle *)device;
4275a69bb27SFrançois Revol
4285a69bb27SFrançois Revol			disk_identifier& disk = drive->Identifier();
4295a69bb27SFrançois Revol			disk.device.unknown.check_sums[i].offset = offset;
4305a69bb27SFrançois Revol			disk.device.unknown.check_sums[i].sum = compute_check_sum(drive, offset);
4315a69bb27SFrançois Revol
4325a69bb27SFrançois Revol			TRACE(("disk %x, offset %Ld, sum %lu\n", drive->DriveID(), offset,
4335a69bb27SFrançois Revol				disk.device.unknown.check_sums[i].sum));
4345a69bb27SFrançois Revol		}
4355a69bb27SFrançois Revol
4365a69bb27SFrançois Revol		index++;
4375a69bb27SFrançois Revol	}
4385a69bb27SFrançois Revol
4395a69bb27SFrançois Revol	// If we get here, we couldn't find a way to differentiate all disks from each other.
4405a69bb27SFrançois Revol	// It's very likely that one disk is an exact copy of the other, so there is nothing
4415a69bb27SFrançois Revol	// we could do, anyway.
4425a69bb27SFrançois Revol
4435a69bb27SFrançois Revol	dprintf("Could not make BIOS drives unique! Might boot from the wrong disk...\n");
4445a69bb27SFrançois Revol}
4455a69bb27SFrançois Revol
4465a69bb27SFrançois Revol
4475a69bb27SFrançois Revolstatic status_t
4485a69bb27SFrançois Revoladd_block_devices(NodeList *devicesList, bool identifierMissing)
4495a69bb27SFrançois Revol{
4501906acb2SFrançois Revol	int32 map;
4511906acb2SFrançois Revol	uint8 driveID;
45289ae49c7SFrançois Revol	uint8 driveCount = 0;
4531906acb2SFrançois Revol
4545a69bb27SFrançois Revol	if (sBlockDevicesAdded)
4555a69bb27SFrançois Revol		return B_OK;
4565a69bb27SFrançois Revol
457b516effeSFrançois Revol	if (init_xhdi() >= B_OK) {
458b516effeSFrançois Revol		uint16 major;
459b516effeSFrançois Revol		uint16 minor;
460b516effeSFrançois Revol		uint32 blocksize;
4613bf72d19SFrançois Revol		uint32 blocksize2;
462b516effeSFrançois Revol		uint32 blocks;
463b516effeSFrançois Revol		uint32 devflags;
464b516effeSFrançois Revol		uint32 lastacc;
465b516effeSFrançois Revol		char product[33];
466b516effeSFrançois Revol		int32 err;
467b516effeSFrançois Revol
468b516effeSFrançois Revol		map = XHDrvMap();
469b516effeSFrançois Revol		dprintf("XDrvMap() 0x%08lx\n", map);
470b516effeSFrançois Revol		// sadly XDrvmap() has the same issues as XBIOS, it only lists known partitions.
471b516effeSFrançois Revol		// so we just iterate on each major and try to see if there is something.
472b516effeSFrançois Revol		for (driveID = 0; driveID < 32; driveID++) {
473b516effeSFrançois Revol			uint32 startsect;
474b516effeSFrançois Revol			err = XHInqDev(driveID, &major, &minor, &startsect, NULL);
475b516effeSFrançois Revol			if (err < 0) {
476b516effeSFrançois Revol				;//dprintf("XHInqDev(%d) error %d\n", driveID, err);
477b516effeSFrançois Revol			} else {
478b516effeSFrançois Revol				dprintf("XHInqDev(%d): (%d,%d):%d\n", driveID, major, minor, startsect);
479b516effeSFrançois Revol			}
4805a69bb27SFrançois Revol		}
4815a69bb27SFrançois Revol
482b516effeSFrançois Revol		product[32] = '\0';
483b516effeSFrançois Revol		for (major = 0; major < 256; major++) {
484b516effeSFrançois Revol			if (major == 64) // we don't want floppies
485b516effeSFrançois Revol				continue;
486f77b0a6bSFrançois Revol			if (major > 23 && major != 64) // extensions and non-standard stuff... skip for speed.
487b516effeSFrançois Revol				break;
488b516effeSFrançois Revol
489b516effeSFrançois Revol			for (minor = 0; minor < 255; minor++) {
490b516effeSFrançois Revol				if (minor && (major < 8 || major >15))
491b516effeSFrançois Revol					break; // minor only used for the SCSI LUN AFAIK.
492b516effeSFrançois Revol				if (minor > 15) // are more used at all ?
493b516effeSFrançois Revol					break;
494b516effeSFrançois Revol
495b516effeSFrançois Revol				product[0] = '\0';
496b516effeSFrançois Revol				blocksize = 0;
4973bf72d19SFrançois Revol				blocksize2 = 0;
498b516effeSFrançois Revol#if 0
499b516effeSFrançois Revol				err = XHLastAccess(major, minor, &lastacc);
500b516effeSFrançois Revol				if (err < 0) {
501b516effeSFrançois Revol					;//dprintf("XHLastAccess(%d,%d) error %d\n", major, minor, err);
502b516effeSFrançois Revol				} else
503b516effeSFrançois Revol					dprintf("XHLastAccess(%d,%d): %ld\n", major, minor, lastacc);
504b516effeSFrançois Revol//continue;
505b516effeSFrançois Revol#endif
506b516effeSFrançois Revol				// we can pass NULL pointers but just to play safe we don't.
507b516effeSFrançois Revol				err = XHInqTarget(major, minor, &blocksize, &devflags, product);
508b516effeSFrançois Revol				if (err < 0) {
509b516effeSFrançois Revol					dprintf("XHInqTarget(%d,%d) error %d\n", major, minor, err);
510b516effeSFrançois Revol					continue;
511b516effeSFrançois Revol				}
5123bf72d19SFrançois Revol				err = XHGetCapacity(major, minor, &blocks, &blocksize2);
513b516effeSFrançois Revol				if (err < 0) {
514b516effeSFrançois Revol					//dprintf("XHGetCapacity(%d,%d) error %d\n", major, minor, err);
515b516effeSFrançois Revol					continue;
516b516effeSFrançois Revol				}
517b516effeSFrançois Revol
5183bf72d19SFrançois Revol				if (blocksize == 0) {
5193bf72d19SFrançois Revol					dprintf("XHDI: blocksize for (%d,%d) is 0!\n", major, minor);
5203bf72d19SFrançois Revol				}
5213bf72d19SFrançois Revol				//dprintf("XHDI: (%d,%d) blocksize1 %ld blocksize2 %ld\n", major, minor, blocksize, blocksize2);
5223bf72d19SFrançois Revol
523b516effeSFrançois Revol				dprintf("XHDI(%d,%d): blksize %d, blocks %d, flags 0x%08lx, '%s'\n", major, minor, blocksize, blocks, devflags, product);
524b516effeSFrançois Revol				driveID = (uint8)major;
5255a69bb27SFrançois Revol
526b516effeSFrançois Revol				//if (driveID == gBootDriveID)
527b516effeSFrançois Revol				//	continue;
528b516effeSFrançois Revol//continue;
529b516effeSFrançois Revol
530b516effeSFrançois Revol				BlockHandle *drive = new(nothrow) XHDIDrive(driveID, major, minor);
531b516effeSFrançois Revol				if (drive->InitCheck() != B_OK) {
532b516effeSFrançois Revol					dprintf("could not add drive (%d,%d)\n", major, minor);
533b516effeSFrançois Revol					delete drive;
534b516effeSFrançois Revol					continue;
535b516effeSFrançois Revol				}
536b516effeSFrançois Revol
537b516effeSFrançois Revol				devicesList->Add(drive);
538b516effeSFrançois Revol				driveCount++;
539b516effeSFrançois Revol
540b516effeSFrançois Revol				if (drive->FillIdentifier() != B_OK)
541b516effeSFrançois Revol					identifierMissing = true;
542b516effeSFrançois Revol			}
543b516effeSFrançois Revol		}
544b516effeSFrançois Revol	}
545b516effeSFrançois Revol	if (!driveCount) { // try to fallback to BIOS XXX: use MetaDOS
546b516effeSFrançois Revol		map = Drvmap();
547b516effeSFrançois Revol		dprintf("Drvmap(): 0x%08lx\n", map);
548b516effeSFrançois Revol		for (driveID = 0; driveID < 32; driveID++) {
549b516effeSFrançois Revol			bool present = map & 0x1;
550b516effeSFrançois Revol			map >>= 1;
551b516effeSFrançois Revol			if (!present)
552b516effeSFrançois Revol				continue;
553b516effeSFrançois Revol
554b516effeSFrançois Revol			if (driveID == gBootDriveID)
555b516effeSFrançois Revol				continue;
556b516effeSFrançois Revol
557b516effeSFrançois Revol			BlockHandle *drive = new(nothrow) BlockHandle(driveID);
558b516effeSFrançois Revol			if (drive->InitCheck() != B_OK) {
559b516effeSFrançois Revol				dprintf("could not add drive %u\n", driveID);
560b516effeSFrançois Revol				delete drive;
561b516effeSFrançois Revol				continue;
562b516effeSFrançois Revol			}
563b516effeSFrançois Revol
564b516effeSFrançois Revol			devicesList->Add(drive);
565b516effeSFrançois Revol			driveCount++;
566b516effeSFrançois Revol
567b516effeSFrançois Revol			if (drive->FillIdentifier() != B_OK)
568b516effeSFrançois Revol				identifierMissing = true;
569b516effeSFrançois Revol		}
5705a69bb27SFrançois Revol	}
5711906acb2SFrançois Revol	dprintf("number of drives: %d\n", driveCount);
5725a69bb27SFrançois Revol
5735a69bb27SFrançois Revol	if (identifierMissing) {
5745a69bb27SFrançois Revol		// we cannot distinguish between all drives by identifier, we need
5755a69bb27SFrançois Revol		// compute checksums for them
5765a69bb27SFrançois Revol		find_unique_check_sums(devicesList);
5775a69bb27SFrançois Revol	}
5785a69bb27SFrançois Revol
5795a69bb27SFrançois Revol	sBlockDevicesAdded = true;
5805a69bb27SFrançois Revol	return B_OK;
5815a69bb27SFrançois Revol}
5825a69bb27SFrançois Revol
5835a69bb27SFrançois Revol
5845a69bb27SFrançois Revol//	#pragma mark -
5855a69bb27SFrançois Revol
5865a69bb27SFrançois Revol
5875a69bb27SFrançois RevolBlockHandle::BlockHandle(int handle)
5885a69bb27SFrançois Revol	: Handle(handle)
589f77b0a6bSFrançois Revol	, fSize(0LL)
590f77b0a6bSFrançois Revol	, fBlockSize(0)
591f77b0a6bSFrançois Revol	, fHasParameters(false)
592f77b0a6bSFrançois Revol
5935a69bb27SFrançois Revol{
5943bf72d19SFrançois Revol	TRACE(("BlockHandle::%s(): drive ID %u\n", __FUNCTION__, fHandle));
595d4d03238SFrançois Revol}
596d4d03238SFrançois Revol
597d4d03238SFrançois Revol
598d4d03238SFrançois RevolBlockHandle::~BlockHandle()
599d4d03238SFrançois Revol{
600d4d03238SFrançois Revol}
6015a69bb27SFrançois Revol
602d4d03238SFrançois Revol
603d4d03238SFrançois Revolssize_t
604d4d03238SFrançois RevolBlockHandle::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize)
605d4d03238SFrançois Revol{
606d4d03238SFrançois Revol	ssize_t ret;
607d4d03238SFrançois Revol	uint32 offset = pos % fBlockSize;
608d4d03238SFrançois Revol	pos /= fBlockSize;
6093bf72d19SFrançois Revol	TRACE(("BlockHandle::%s: (%d) %Ld, %d\n", __FUNCTION__, fHandle, pos, bufferSize));
610d4d03238SFrançois Revol
611d4d03238SFrançois Revol	uint32 blocksLeft = (bufferSize + offset + fBlockSize - 1) / fBlockSize;
612d4d03238SFrançois Revol	int32 totalBytesRead = 0;
613d4d03238SFrançois Revol
6143ef0397bSFrançois Revol	//TRACE(("BIOS reads %lu bytes from %Ld (offset = %lu)\n",
6153ef0397bSFrançois Revol	//	blocksLeft * fBlockSize, pos * fBlockSize, offset));
616d4d03238SFrançois Revol
617d4d03238SFrançois Revol	// read partial block
618d4d03238SFrançois Revol	if (offset) {
619588b2cd4SFrançois Revol		ret = ReadBlocks(gScratchBuffer, pos, 1);
620d4d03238SFrançois Revol		if (ret < 0)
621588b2cd4SFrançois Revol			return ret;
622d4d03238SFrançois Revol		totalBytesRead += fBlockSize - offset;
623d4d03238SFrançois Revol		memcpy(buffer, gScratchBuffer + offset, totalBytesRead);
624d4d03238SFrançois Revol
625d4d03238SFrançois Revol	}
626d4d03238SFrançois Revol
627d4d03238SFrançois Revol	uint32 scratchSize = SCRATCH_SIZE / fBlockSize;
628d4d03238SFrançois Revol
629d4d03238SFrançois Revol	while (blocksLeft > 0) {
630d4d03238SFrançois Revol		uint32 blocksRead = blocksLeft;
631d4d03238SFrançois Revol		if (blocksRead > scratchSize)
632d4d03238SFrançois Revol			blocksRead = scratchSize;
633d4d03238SFrançois Revol
634d4d03238SFrançois Revol		ret = ReadBlocks(gScratchBuffer, pos, blocksRead);
635d4d03238SFrançois Revol		if (ret < 0)
636d4d03238SFrançois Revol			return ret;
637d4d03238SFrançois Revol
638d4d03238SFrançois Revol		uint32 bytesRead = fBlockSize * blocksRead - offset;
639d4d03238SFrançois Revol		// copy no more than bufferSize bytes
640d4d03238SFrançois Revol		if (bytesRead > bufferSize)
641d4d03238SFrançois Revol			bytesRead = bufferSize;
642d4d03238SFrançois Revol
643d4d03238SFrançois Revol		memcpy(buffer, (void *)(gScratchBuffer + offset), bytesRead);
644d4d03238SFrançois Revol		pos += blocksRead;
645d4d03238SFrançois Revol		offset = 0;
646d4d03238SFrançois Revol		blocksLeft -= blocksRead;
647d4d03238SFrançois Revol		bufferSize -= bytesRead;
648d4d03238SFrançois Revol		buffer = (void *)((addr_t)buffer + bytesRead);
649d4d03238SFrançois Revol		totalBytesRead += bytesRead;
650d4d03238SFrançois Revol	}
651d4d03238SFrançois Revol
6523ef0397bSFrançois Revol	//TRACE(("BlockHandle::%s: %d bytes read\n", __FUNCTION__, totalBytesRead));
653d4d03238SFrançois Revol	return totalBytesRead;
654d4d03238SFrançois Revol}
655d4d03238SFrançois Revol
656d4d03238SFrançois Revol
657d4d03238SFrançois Revolssize_t
658d4d03238SFrançois RevolBlockHandle::WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize)
659d4d03238SFrançois Revol{
660d4d03238SFrançois Revol	// we don't have to know how to write
661d4d03238SFrançois Revol	return B_NOT_ALLOWED;
662d4d03238SFrançois Revol}
663d4d03238SFrançois Revol
664d4d03238SFrançois Revol
665d4d03238SFrançois Revolssize_t
666d4d03238SFrançois RevolBlockHandle::ReadBlocks(void *buffer, off_t first, int32 count)
667d4d03238SFrançois Revol{
668d4d03238SFrançois Revol	return B_NOT_ALLOWED;
669d4d03238SFrançois Revol}
670d4d03238SFrançois Revol
671d4d03238SFrançois Revol
672588b2cd4SFrançois Revolstatus_t
673d4d03238SFrançois RevolBlockHandle::FillIdentifier()
674d4d03238SFrançois Revol{
675d4d03238SFrançois Revol	return B_NOT_ALLOWED;
676588b2cd4SFrançois Revol}
677d4d03238SFrançois Revol
678f77b0a6bSFrançois Revol//	#pragma mark -
679f77b0a6bSFrançois Revol
680f77b0a6bSFrançois Revol/*
681f77b0a6bSFrançois Revol * BIOS based disk access.
682f77b0a6bSFrançois Revol * Only for fallback from missing XHDI.
683f77b0a6bSFrançois Revol * XXX: This is broken!
684f77b0a6bSFrançois Revol * XXX: check for physical drives in PUN_INFO
685f77b0a6bSFrançois Revol * XXX: at least try to use MetaDOS calls instead.
686f77b0a6bSFrançois Revol */
687f77b0a6bSFrançois Revol
688f77b0a6bSFrançois Revol
689f77b0a6bSFrançois RevolFloppyDrive::FloppyDrive(int handle)
690f77b0a6bSFrançois Revol	: BlockHandle(handle)
691f77b0a6bSFrançois Revol{
692f77b0a6bSFrançois Revol	TRACE(("FloppyDrive::%s(%d)\n", __FUNCTION__, fHandle));
693f77b0a6bSFrançois Revol
694f77b0a6bSFrançois Revol	/* first check if the drive exists */
695f77b0a6bSFrançois Revol	/* note floppy B can be reported present anyway... */
696f77b0a6bSFrançois Revol	uint32 map = Drvmap();
697f77b0a6bSFrançois Revol	if (!(map & (1 << fHandle))) {
698f77b0a6bSFrançois Revol		fSize = 0LL;
699f77b0a6bSFrançois Revol		return;
700f77b0a6bSFrançois Revol	}
701f77b0a6bSFrançois Revol	//XXX: check size
702f77b0a6bSFrançois Revol
703f77b0a6bSFrançois Revol	if (get_drive_parameters(fHandle, &fParameters) != B_OK) {
704f77b0a6bSFrançois Revol		dprintf("getting drive parameters for: %u failed!\n", fHandle);
705f77b0a6bSFrançois Revol		return;
706f77b0a6bSFrançois Revol	}
70712442ce5SFrançois Revol	// XXX: probe! this is a std 1.44kB floppy
708f77b0a6bSFrançois Revol	fBlockSize = 512;
709f77b0a6bSFrançois Revol	fParameters.sectors = 1440 * 1024 / 512;
71012442ce5SFrançois Revol	fParameters.sectors_per_track = 18;
71112442ce5SFrançois Revol	fParameters.heads = 2;
712f77b0a6bSFrançois Revol	fSize = fParameters.sectors * fBlockSize;
713f77b0a6bSFrançois Revol	fHasParameters = false;
714f77b0a6bSFrançois Revol/*
715f77b0a6bSFrançois Revol	parameters->sectors_per_track = 9;
716f77b0a6bSFrançois Revol	parameters->cylinders = (1440/2) / (9*2);
717f77b0a6bSFrançois Revol	parameters->heads = 2;
718f77b0a6bSFrançois Revol	parameters->sectors = parameters->cylinders * parameters->heads
719f77b0a6bSFrançois Revol	* parameters->sectors_per_track;
720f77b0a6bSFrançois Revol	*/
721f77b0a6bSFrançois Revol#if 0
722f77b0a6bSFrançois Revol	if (get_ext_drive_parameters(driveID, &fParameters) != B_OK) {
723f77b0a6bSFrançois Revol		// old style CHS support
724f77b0a6bSFrançois Revol
725f77b0a6bSFrançois Revol		if (get_drive_parameters(driveID, &fParameters) != B_OK) {
726f77b0a6bSFrançois Revol			dprintf("getting drive parameters for: %u failed!\n", fDriveID);
727f77b0a6bSFrançois Revol			return;
728f77b0a6bSFrançois Revol		}
729f77b0a6bSFrançois Revol
730f77b0a6bSFrançois Revol		TRACE(("  cylinders: %lu, heads: %lu, sectors: %lu, bytes_per_sector: %u\n",
731f77b0a6bSFrançois Revol			fParameters.cylinders, fParameters.heads, fParameters.sectors_per_track,
732f77b0a6bSFrançois Revol			fParameters.bytes_per_sector));
733f77b0a6bSFrançois Revol		TRACE(("  total sectors: %Ld\n", fParameters.sectors));
734f77b0a6bSFrançois Revol
735f77b0a6bSFrançois Revol		fBlockSize = 512;
736f77b0a6bSFrançois Revol		fSize = fParameters.sectors * fBlockSize;
737f77b0a6bSFrançois Revol		fLBA = false;
738f77b0a6bSFrançois Revol		fHasParameters = false;
739f77b0a6bSFrançois Revol	} else {
740f77b0a6bSFrançois Revol		TRACE(("size: %x\n", fParameters.parameters_size));
741f77b0a6bSFrançois Revol		TRACE(("drive_path_signature: %x\n", fParameters.device_path_signature));
742f77b0a6bSFrançois Revol		TRACE(("host bus: \"%s\", interface: \"%s\"\n", fParameters.host_bus,
743f77b0a6bSFrançois Revol			fParameters.interface_type));
744f77b0a6bSFrançois Revol		TRACE(("cylinders: %lu, heads: %lu, sectors: %lu, bytes_per_sector: %u\n",
745f77b0a6bSFrançois Revol			fParameters.cylinders, fParameters.heads, fParameters.sectors_per_track,
746f77b0a6bSFrançois Revol			fParameters.bytes_per_sector));
747f77b0a6bSFrançois Revol		TRACE(("total sectors: %Ld\n", fParameters.sectors));
748f77b0a6bSFrançois Revol
749f77b0a6bSFrançois Revol		fBlockSize = fParameters.bytes_per_sector;
750f77b0a6bSFrançois Revol		fSize = fParameters.sectors * fBlockSize;
751f77b0a6bSFrançois Revol		fLBA = true;
752f77b0a6bSFrançois Revol		fHasParameters = true;
753f77b0a6bSFrançois Revol	}
754f77b0a6bSFrançois Revol#endif
755f77b0a6bSFrançois Revol}
756f77b0a6bSFrançois Revol
757f77b0a6bSFrançois Revol
758f77b0a6bSFrançois RevolFloppyDrive::~FloppyDrive()
759f77b0a6bSFrançois Revol{
760f77b0a6bSFrançois Revol}
761f77b0a6bSFrançois Revol
762f77b0a6bSFrançois Revol
763f77b0a6bSFrançois Revolstatus_t
764f77b0a6bSFrançois RevolFloppyDrive::FillIdentifier()
765f77b0a6bSFrançois Revol{
766f77b0a6bSFrançois Revol	TRACE(("FloppyDrive::%s: (%d)\n", __FUNCTION__, fHandle));
767f77b0a6bSFrançois Revol#if 0
768f77b0a6bSFrançois Revol	if (HasParameters()) {
769f77b0a6bSFrançois Revol		// try all drive_parameters versions, beginning from the most informative
770f77b0a6bSFrançois Revol
771f77b0a6bSFrançois Revol#if 0
772f77b0a6bSFrançois Revol		if (fill_disk_identifier_v3(fIdentifier, fParameters) == B_OK)
773f77b0a6bSFrançois Revol			return B_OK;
774f77b0a6bSFrançois Revol
775f77b0a6bSFrançois Revol		if (fill_disk_identifier_v2(fIdentifier, fParameters) == B_OK)
776f77b0a6bSFrançois Revol			return B_OK;
777f77b0a6bSFrançois Revol#else
778f77b0a6bSFrançois Revol		// TODO: the above version is the correct one - it's currently
779f77b0a6bSFrançois Revol		//		disabled, as the kernel boot code only supports the
780f77b0a6bSFrançois Revol		//		UNKNOWN_BUS/UNKNOWN_DEVICE way to find the correct boot
781f77b0a6bSFrançois Revol		//		device.
782f77b0a6bSFrançois Revol		if (fill_disk_identifier_v3(fIdentifier, fParameters) != B_OK)
783f77b0a6bSFrançois Revol			fill_disk_identifier_v2(fIdentifier, fParameters);
784f77b0a6bSFrançois Revol
785f77b0a6bSFrançois Revol#endif
786f77b0a6bSFrançois Revol
787f77b0a6bSFrançois Revol		// no interesting information, we have to fall back to the default
788f77b0a6bSFrançois Revol		// unknown interface/device type identifier
789f77b0a6bSFrançois Revol	}
790f77b0a6bSFrançois Revol
791f77b0a6bSFrançois Revol	fIdentifier.bus_type = UNKNOWN_BUS;
792f77b0a6bSFrançois Revol	fIdentifier.device_type = UNKNOWN_DEVICE;
793f77b0a6bSFrançois Revol	fIdentifier.device.unknown.size = Size();
794f77b0a6bSFrançois Revol
795f77b0a6bSFrançois Revol	for (int32 i = 0; i < NUM_DISK_CHECK_SUMS; i++) {
796f77b0a6bSFrançois Revol		fIdentifier.device.unknown.check_sums[i].offset = -1;
797f77b0a6bSFrançois Revol		fIdentifier.device.unknown.check_sums[i].sum = 0;
798f77b0a6bSFrançois Revol	}
799f77b0a6bSFrançois Revol#endif
800f77b0a6bSFrançois Revol
801f77b0a6bSFrançois Revol	return B_ERROR;
802f77b0a6bSFrançois Revol}
803f77b0a6bSFrançois Revol
804f77b0a6bSFrançois Revol
80512442ce5SFrançois Revolstatic void
80612442ce5SFrançois Revolhexdump(uint8 *buf, uint32 offset)
80712442ce5SFrançois Revol{
80812442ce5SFrançois Revol// hexdump
80912442ce5SFrançois Revol
81012442ce5SFrançois Revol	for (int i = 0; i < 512; i++) {
81112442ce5SFrançois Revol		if ((i % 16) == 0)
81212442ce5SFrançois Revol			TRACE(("%08lx ", offset+i));
81312442ce5SFrançois Revol		if ((i % 16) == 8)
81412442ce5SFrançois Revol		TRACE((" "));
81512442ce5SFrançois Revol		TRACE((" %02x", buf[i]));
81612442ce5SFrançois Revol
81712442ce5SFrançois Revol		if ((i % 16) == 15)
81812442ce5SFrançois Revol			TRACE(("\n"));
81912442ce5SFrançois Revol	}
82012442ce5SFrançois Revol}
82112442ce5SFrançois Revol
82212442ce5SFrançois Revol
823f77b0a6bSFrançois Revolssize_t
824f77b0a6bSFrançois RevolFloppyDrive::ReadBlocks(void *buffer, off_t first, int32 count)
825f77b0a6bSFrançois Revol{
826f77b0a6bSFrançois Revol	int sectorsPerBlocks = (fBlockSize / 512);
82712442ce5SFrançois Revol	int sectorsPerTrack = fParameters.sectors_per_track;
82812442ce5SFrançois Revol	int heads = fParameters.heads;
829f77b0a6bSFrançois Revol	int32 ret;
83012442ce5SFrançois Revol	//TRACE(("FloppyDrive::%s(%Ld,%ld) (%d)\n", __FUNCTION__, first, count, fHandle));
831f77b0a6bSFrançois Revol	// force single sector reads to avoid crossing track boundaries
832f77b0a6bSFrançois Revol	for (int i = 0; i < count; i++) {
833f77b0a6bSFrançois Revol		uint8 *buf = (uint8 *)buffer;
834f77b0a6bSFrançois Revol		buf += i * fBlockSize;
835f77b0a6bSFrançois Revol
836f77b0a6bSFrançois Revol		int16 track, side, sect;
837f77b0a6bSFrançois Revol		sect = (first + i) * sectorsPerBlocks;
83812442ce5SFrançois Revol		track = sect / (sectorsPerTrack * heads);
83912442ce5SFrançois Revol		side = (sect / sectorsPerTrack) % heads;
84012442ce5SFrançois Revol		sect %= sectorsPerTrack;
841f77b0a6bSFrançois Revol		sect++; // 1-based
842f77b0a6bSFrançois Revol
843f77b0a6bSFrançois Revol
84412442ce5SFrançois Revol		/*
84512442ce5SFrançois Revol		  TRACE(("FloppyDrive::%s: THS: %d %d %d\n",
84612442ce5SFrançois Revol		  __FUNCTION__, track, side, sect));
84712442ce5SFrançois Revol		*/
848f77b0a6bSFrançois Revol		ret = Floprd(buf, 0L, fHandle, sect, track, side, 1);
849f77b0a6bSFrançois Revol		if (ret < 0)
850f77b0a6bSFrançois Revol			return toserror(ret);
85112442ce5SFrançois Revol		//if (first >= 1440)
85212442ce5SFrançois Revol		//hexdump(buf, (uint32)(first+i)*512);
853f77b0a6bSFrançois Revol	}
85412442ce5SFrançois Revol
855f77b0a6bSFrançois Revol	return count;
856f77b0a6bSFrançois Revol}
857f77b0a6bSFrançois Revol
858f77b0a6bSFrançois Revol
859d4d03238SFrançois Revol//	#pragma mark -
860d4d03238SFrançois Revol
861d4d03238SFrançois Revol/*
862d4d03238SFrançois Revol * BIOS based disk access.
863d4d03238SFrançois Revol * Only for fallback from missing XHDI.
864d4d03238SFrançois Revol * XXX: This is broken!
865d4d03238SFrançois Revol * XXX: check for physical drives in PUN_INFO
866d4d03238SFrançois Revol * XXX: at least try to use MetaDOS calls instead.
867d4d03238SFrançois Revol */
868d4d03238SFrançois Revol
869d4d03238SFrançois Revol
870d4d03238SFrançois RevolBIOSDrive::BIOSDrive(int handle)
871d4d03238SFrançois Revol	: BlockHandle(handle)
872d4d03238SFrançois Revol{
8733bf72d19SFrançois Revol	TRACE(("BIOSDrive::%s(%d)\n", __FUNCTION__, fHandle));
8743bf72d19SFrançois Revol
8755a69bb27SFrançois Revol	/* first check if the drive exists */
8765a69bb27SFrançois Revol	/* note floppy B can be reported present anyway... */
8775a69bb27SFrançois Revol	uint32 map = Drvmap();
8785a69bb27SFrançois Revol	if (!(map & (1 << fHandle))) {
8795a69bb27SFrançois Revol		fSize = 0LL;
8805a69bb27SFrançois Revol		return;
8815a69bb27SFrançois Revol	}
8825a69bb27SFrançois Revol	//XXX: check size
8835a69bb27SFrançois Revol
88489ae49c7SFrançois Revol	if (get_drive_parameters(fHandle, &fParameters) != B_OK) {
88589ae49c7SFrançois Revol		dprintf("getting drive parameters for: %u failed!\n", fHandle);
88689ae49c7SFrançois Revol		return;
88789ae49c7SFrançois Revol	}
88889ae49c7SFrançois Revol	fBlockSize = 512;
88989ae49c7SFrançois Revol	fSize = fParameters.sectors * fBlockSize;
89089ae49c7SFrançois Revol	fHasParameters = false;
89189ae49c7SFrançois Revol
89289ae49c7SFrançois Revol#if 0
8935a69bb27SFrançois Revol	if (get_ext_drive_parameters(driveID, &fParameters) != B_OK) {
8945a69bb27SFrançois Revol		// old style CHS support
8955a69bb27SFrançois Revol
8965a69bb27SFrançois Revol		if (get_drive_parameters(driveID, &fParameters) != B_OK) {
8975a69bb27SFrançois Revol			dprintf("getting drive parameters for: %u failed!\n", fDriveID);
8985a69bb27SFrançois Revol			return;
8995a69bb27SFrançois Revol		}
9005a69bb27SFrançois Revol
9015a69bb27SFrançois Revol		TRACE(("  cylinders: %lu, heads: %lu, sectors: %lu, bytes_per_sector: %u\n",
9025a69bb27SFrançois Revol			fParameters.cylinders, fParameters.heads, fParameters.sectors_per_track,
9035a69bb27SFrançois Revol			fParameters.bytes_per_sector));
9045a69bb27SFrançois Revol		TRACE(("  total sectors: %Ld\n", fParameters.sectors));
9055a69bb27SFrançois Revol
9065a69bb27SFrançois Revol		fBlockSize = 512;
9075a69bb27SFrançois Revol		fSize = fParameters.sectors * fBlockSize;
9085a69bb27SFrançois Revol		fLBA = false;
9095a69bb27SFrançois Revol		fHasParameters = false;
9105a69bb27SFrançois Revol	} else {
9115a69bb27SFrançois Revol		TRACE(("size: %x\n", fParameters.parameters_size));
9125a69bb27SFrançois Revol		TRACE(("drive_path_signature: %x\n", fParameters.device_path_signature));
9135a69bb27SFrançois Revol		TRACE(("host bus: \"%s\", interface: \"%s\"\n", fParameters.host_bus,
9145a69bb27SFrançois Revol			fParameters.interface_type));
9155a69bb27SFrançois Revol		TRACE(("cylinders: %lu, heads: %lu, sectors: %lu, bytes_per_sector: %u\n",
9165a69bb27SFrançois Revol			fParameters.cylinders, fParameters.heads, fParameters.sectors_per_track,
9175a69bb27SFrançois Revol			fParameters.bytes_per_sector));
9185a69bb27SFrançois Revol		TRACE(("total sectors: %Ld\n", fParameters.sectors));
9195a69bb27SFrançois Revol
9205a69bb27SFrançois Revol		fBlockSize = fParameters.bytes_per_sector;
9215a69bb27SFrançois Revol		fSize = fParameters.sectors * fBlockSize;
9225a69bb27SFrançois Revol		fLBA = true;
9235a69bb27SFrançois Revol		fHasParameters = true;
9245a69bb27SFrançois Revol	}
92589ae49c7SFrançois Revol#endif
9265a69bb27SFrançois Revol}
9275a69bb27SFrançois Revol
9285a69bb27SFrançois Revol
929d4d03238SFrançois RevolBIOSDrive::~BIOSDrive()
9305a69bb27SFrançois Revol{
9315a69bb27SFrançois Revol}
9325a69bb27SFrançois Revol
9335a69bb27SFrançois Revol
9345a69bb27SFrançois Revolstatus_t
935d4d03238SFrançois RevolBIOSDrive::FillIdentifier()
9365a69bb27SFrançois Revol{
9373bf72d19SFrançois Revol	TRACE(("BIOSDrive::%s: (%d)\n", __FUNCTION__, fHandle));
93889ae49c7SFrançois Revol#if 0
9395a69bb27SFrançois Revol	if (HasParameters()) {
9405a69bb27SFrançois Revol		// try all drive_parameters versions, beginning from the most informative
9415a69bb27SFrançois Revol
9425a69bb27SFrançois Revol#if 0
9435a69bb27SFrançois Revol		if (fill_disk_identifier_v3(fIdentifier, fParameters) == B_OK)
9445a69bb27SFrançois Revol			return B_OK;
9455a69bb27