xref: /haiku/src/system/boot/platform/atari_m68k/devices.cpp (revision a381c8a06378de22ff08adf4282b4e3f7e50d250)
1 /*
2  * Copyright 2003-2006, Axel Dörfler, axeld@pinc-software.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include <KernelExport.h>
8 #include <boot/platform.h>
9 #include <boot/partitions.h>
10 #include <boot/stdio.h>
11 #include <boot/stage2.h>
12 
13 #include <string.h>
14 
15 #include "Handle.h"
16 #include "toscalls.h"
17 
18 #define TRACE_DEVICES
19 #ifdef TRACE_DEVICES
20 #	define TRACE(x) dprintf x
21 #else
22 #	define TRACE(x) ;
23 #endif
24 
25 
26 // exported from shell.S
27 extern uint8 gBootedFromImage;
28 extern uint8 gBootDriveID;
29 extern uint32 gBootPartitionOffset;
30 
31 #define SCRATCH_SIZE (2*4096)
32 static uint8 gScratchBuffer[4096];
33 
34 static const uint16 kParametersSizeVersion1 = sizeof(struct tos_bpb);
35 static const uint16 kParametersSizeVersion2 = 0x1e;
36 static const uint16 kParametersSizeVersion3 = 0x42;
37 
38 static const uint16 kDevicePathSignature = 0xbedd;
39 
40 //XXX clean this up!
41 struct drive_parameters {
42 	struct tos_bpb bpb;
43 	uint16		parameters_size;
44 	uint16		flags;
45 	uint32		cylinders;
46 	uint32		heads;
47 	uint32		sectors_per_track;
48 	uint64		sectors;
49 	uint16		bytes_per_sector;
50 	/* edd 2.0 */
51 	//real_addr	device_table;
52 	/* edd 3.0 */
53 	uint16		device_path_signature;
54 	uint8		device_path_size;
55 	uint8		reserved1[3];
56 	char		host_bus[4];
57 	char		interface_type[8];
58 	union {
59 		struct {
60 			uint16	base_address;
61 		} legacy;
62 		struct {
63 			uint8	bus;
64 			uint8	slot;
65 			uint8	function;
66 		} pci;
67 		uint8		reserved[8];
68 	} interface;
69 	union {
70 		struct {
71 			uint8	slave;
72 		} ata;
73 		struct {
74 			uint8	slave;
75 			uint8	logical_unit;
76 		} atapi;
77 		struct {
78 			uint8	logical_unit;
79 		} scsi;
80 		struct {
81 			uint8	tbd;
82 		} usb;
83 		struct {
84 			uint64	guid;
85 		} firewire;
86 		struct {
87 			uint64	wwd;
88 		} fibre;
89 	} device;
90 	uint8		reserved2;
91 	uint8		checksum;
92 } _PACKED;
93 
94 struct device_table {
95 	uint16	base_address;
96 	uint16	control_port_address;
97 	uint8	_reserved1 : 4;
98 	uint8	is_slave : 1;
99 	uint8	_reserved2 : 1;
100 	uint8	lba_enabled : 1;
101 } _PACKED;
102 
103 struct specification_packet {
104 	uint8	size;
105 	uint8	media_type;
106 	uint8	drive_number;
107 	uint8	controller_index;
108 	uint32	start_emulation;
109 	uint16	device_specification;
110 	uint8	_more_[9];
111 } _PACKED;
112 
113 class BlockHandle : public Handle {
114 	public:
115 		BlockHandle(int handle);
116 		virtual ~BlockHandle();
117 
118 		virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize);
119 		virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize);
120 
121 		virtual off_t Size() const { return fSize; };
122 
123 		uint32 BlockSize() const { return fBlockSize; }
124 
125 		bool HasParameters() const { return fHasParameters; }
126 		const drive_parameters &Parameters() const { return fParameters; }
127 
128 		virtual status_t FillIdentifier();
129 
130 		disk_identifier &Identifier() { return fIdentifier; }
131 		uint8 DriveID() const { return fHandle; }
132 		status_t InitCheck() const { return fSize > 0 ? B_OK : B_ERROR; };
133 
134 
135 
136 		virtual ssize_t ReadBlocks(void *buffer, off_t first, int32 count);
137 
138 	protected:
139 		uint64	fSize;
140 		uint32	fBlockSize;
141 		bool	fHasParameters;
142 		drive_parameters fParameters;
143 		disk_identifier fIdentifier;
144 };
145 
146 
147 class BIOSDrive : public BlockHandle {
148 	public:
149 		BIOSDrive(int handle);
150 		virtual ~BIOSDrive();
151 
152 		status_t FillIdentifier();
153 
154 		virtual ssize_t ReadBlocks(void *buffer, off_t first, int32 count);
155 
156 	protected:
157 		status_t	ReadBPB(struct tos_bpb *bpb);
158 };
159 
160 
161 class XHDIDrive : public BlockHandle {
162 	public:
163 		XHDIDrive(int handle, uint16 major, uint16 minor);
164 		virtual ~XHDIDrive();
165 
166 		status_t FillIdentifier();
167 
168 		virtual ssize_t ReadBlocks(void *buffer, off_t first, int32 count);
169 
170 	protected:
171 		uint16 fMajor;
172 		uint16 fMinor;
173 };
174 
175 
176 static bool sBlockDevicesAdded = false;
177 
178 
179 static status_t
180 read_bpb(uint8 drive, struct tos_bpb *bpb)
181 {
182 	struct tos_bpb *p;
183 	p = Getbpb(drive);
184 	memcpy(bpb, p, sizeof(struct tos_bpb));
185 	/* Getbpb is buggy so we must force a media change */
186 	//XXX: docs seems to assume we should loop until it works
187 	Mediach(drive);
188 	return B_OK;
189 }
190 
191 static status_t
192 get_drive_parameters(uint8 drive, drive_parameters *parameters)
193 {
194 	status_t err;
195 	err = read_bpb(drive, &parameters->bpb);
196 
197 #if 0
198 	// fill drive_parameters structure with useful values
199 	parameters->parameters_size = kParametersSizeVersion1;
200 	parameters->flags = 0;
201 	parameters->cylinders = (((regs.ecx & 0xc0) << 2) | ((regs.ecx >> 8) & 0xff)) + 1;
202 	parameters->heads = ((regs.edx >> 8) & 0xff) + 1;
203 		// heads and cylinders start counting from 0
204 	parameters->sectors_per_track = regs.ecx & 0x3f;
205 	parameters->sectors = parameters->cylinders * parameters->heads
206 		* parameters->sectors_per_track;
207 	parameters->bytes_per_sector = 512;
208 #endif
209 	return B_OK;
210 }
211 
212 
213 #if 0
214 /** parse EDD 3.0 drive path information */
215 
216 static status_t
217 fill_disk_identifier_v3(disk_identifier &disk, const drive_parameters &parameters)
218 {
219 	if (parameters.parameters_size < kParametersSizeVersion3
220 		|| parameters.device_path_signature != kDevicePathSignature)
221 		return B_BAD_TYPE;
222 
223 	// parse host bus
224 
225 	if (!strncmp(parameters.host_bus, "PCI", 3)) {
226 		disk.bus_type = PCI_BUS;
227 
228 		disk.bus.pci.bus = parameters.interface.pci.bus;
229 		disk.bus.pci.slot = parameters.interface.pci.slot;
230 		disk.bus.pci.function = parameters.interface.pci.function;
231 	} else if (!strncmp(parameters.host_bus, "ISA", 3)) {
232 		disk.bus_type = LEGACY_BUS;
233 
234 		disk.bus.legacy.base_address = parameters.interface.legacy.base_address;
235 		dprintf("legacy base address %x\n", disk.bus.legacy.base_address);
236 	} else {
237 		dprintf("unknown host bus \"%s\"\n", parameters.host_bus);
238 		return B_BAD_DATA;
239 	}
240 
241 	// parse interface
242 
243 	if (!strncmp(parameters.interface_type, "ATA", 3)) {
244 		disk.device_type = ATA_DEVICE;
245 		disk.device.ata.master = !parameters.device.ata.slave;
246 		dprintf("ATA device, %s\n", disk.device.ata.master ? "master" : "slave");
247 	} else if (!strncmp(parameters.interface_type, "ATAPI", 3)) {
248 		disk.device_type = ATAPI_DEVICE;
249 		disk.device.atapi.master = !parameters.device.ata.slave;
250 		disk.device.atapi.logical_unit = parameters.device.atapi.logical_unit;
251 	} else if (!strncmp(parameters.interface_type, "SCSI", 3)) {
252 		disk.device_type = SCSI_DEVICE;
253 		disk.device.scsi.logical_unit = parameters.device.scsi.logical_unit;
254 	} else if (!strncmp(parameters.interface_type, "USB", 3)) {
255 		disk.device_type = USB_DEVICE;
256 		disk.device.usb.tbd = parameters.device.usb.tbd;
257 	} else if (!strncmp(parameters.interface_type, "1394", 3)) {
258 		disk.device_type = FIREWIRE_DEVICE;
259 		disk.device.firewire.guid = parameters.device.firewire.guid;
260 	} else if (!strncmp(parameters.interface_type, "FIBRE", 3)) {
261 		disk.device_type = FIBRE_DEVICE;
262 		disk.device.fibre.wwd = parameters.device.fibre.wwd;
263 	} else {
264 		dprintf("unknown interface type \"%s\"\n", parameters.interface_type);
265 		return B_BAD_DATA;
266 	}
267 
268 	return B_OK;
269 }
270 
271 
272 /** EDD 2.0 drive table information */
273 
274 static status_t
275 fill_disk_identifier_v2(disk_identifier &disk, const drive_parameters &parameters)
276 {
277 	if (parameters.device_table.segment == 0xffff
278 		&& parameters.device_table.offset == 0xffff)
279 		return B_BAD_TYPE;
280 
281 	device_table *table = (device_table *)LINEAR_ADDRESS(parameters.device_table.segment,
282 		parameters.device_table.offset);
283 
284 	disk.bus_type = LEGACY_BUS;
285 	disk.bus.legacy.base_address = table->base_address;
286 
287 	disk.device_type = ATA_DEVICE;
288 	disk.device.ata.master = !table->is_slave;
289 
290 	return B_OK;
291 }
292 #endif
293 
294 static off_t
295 get_next_check_sum_offset(int32 index, off_t maxSize)
296 {
297 	// The boot block often contains the disk super block, and should be
298 	// unique enough for most cases
299 	if (index < 2)
300 		return index * 512;
301 
302 	// Try some data in the first part of the drive
303 	if (index < 4)
304 		return (maxSize >> 10) + index * 2048;
305 
306 	// Some random value might do
307 	return ((system_time() + index) % (maxSize >> 9)) * 512;
308 }
309 
310 
311 /**	Computes a check sum for the specified block.
312  *	The check sum is the sum of all data in that block interpreted as an
313  *	array of uint32 values.
314  *	Note, this must use the same method as the one used in kernel/fs/vfs_boot.cpp.
315  */
316 
317 static uint32
318 compute_check_sum(BlockHandle *drive, off_t offset)
319 {
320 	char buffer[512];
321 	ssize_t bytesRead = drive->ReadAt(NULL, offset, buffer, sizeof(buffer));
322 	if (bytesRead < B_OK)
323 		return 0;
324 
325 	if (bytesRead < (ssize_t)sizeof(buffer))
326 		memset(buffer + bytesRead, 0, sizeof(buffer) - bytesRead);
327 
328 	uint32 *array = (uint32 *)buffer;
329 	uint32 sum = 0;
330 
331 	for (uint32 i = 0; i < (bytesRead + sizeof(uint32) - 1) / sizeof(uint32); i++) {
332 		sum += array[i];
333 	}
334 
335 	return sum;
336 }
337 
338 
339 static void
340 find_unique_check_sums(NodeList *devices)
341 {
342 	NodeIterator iterator = devices->GetIterator();
343 	Node *device;
344 	int32 index = 0;
345 	off_t minSize = 0;
346 	const int32 kMaxTries = 200;
347 
348 	while (index < kMaxTries) {
349 		bool clash = false;
350 
351 		iterator.Rewind();
352 
353 		while ((device = iterator.Next()) != NULL) {
354 			BlockHandle *drive = (BlockHandle *)device;
355 #if 0
356 			// there is no RTTI in the boot loader...
357 			BlockHandle *drive = dynamic_cast<BlockHandle *>(device);
358 			if (drive == NULL)
359 				continue;
360 #endif
361 
362 			// TODO: currently, we assume that the BIOS provided us with unique
363 			//	disk identifiers... hopefully this is a good idea
364 			if (drive->Identifier().device_type != UNKNOWN_DEVICE)
365 				continue;
366 
367 			if (minSize == 0 || drive->Size() < minSize)
368 				minSize = drive->Size();
369 
370 			// check for clashes
371 
372 			NodeIterator compareIterator = devices->GetIterator();
373 			while ((device = compareIterator.Next()) != NULL) {
374 				BlockHandle *compareDrive = (BlockHandle *)device;
375 
376 				if (compareDrive == drive
377 					|| compareDrive->Identifier().device_type != UNKNOWN_DEVICE)
378 					continue;
379 
380 				if (!memcmp(&drive->Identifier(), &compareDrive->Identifier(),
381 						sizeof(disk_identifier))) {
382 					clash = true;
383 					break;
384 				}
385 			}
386 
387 			if (clash)
388 				break;
389 		}
390 
391 		if (!clash) {
392 			// our work here is done.
393 			return;
394 		}
395 
396 		// add a new block to the check sums
397 
398 		off_t offset = get_next_check_sum_offset(index, minSize);
399 		int32 i = index % NUM_DISK_CHECK_SUMS;
400 		iterator.Rewind();
401 
402 		while ((device = iterator.Next()) != NULL) {
403 			BlockHandle *drive = (BlockHandle *)device;
404 
405 			disk_identifier& disk = drive->Identifier();
406 			disk.device.unknown.check_sums[i].offset = offset;
407 			disk.device.unknown.check_sums[i].sum = compute_check_sum(drive, offset);
408 
409 			TRACE(("disk %x, offset %Ld, sum %lu\n", drive->DriveID(), offset,
410 				disk.device.unknown.check_sums[i].sum));
411 		}
412 
413 		index++;
414 	}
415 
416 	// If we get here, we couldn't find a way to differentiate all disks from each other.
417 	// It's very likely that one disk is an exact copy of the other, so there is nothing
418 	// we could do, anyway.
419 
420 	dprintf("Could not make BIOS drives unique! Might boot from the wrong disk...\n");
421 }
422 
423 
424 static status_t
425 add_block_devices(NodeList *devicesList, bool identifierMissing)
426 {
427 	int32 map;
428 	uint8 driveID;
429 	uint8 driveCount = 0;
430 
431 	if (sBlockDevicesAdded)
432 		return B_OK;
433 
434 	if (init_xhdi() >= B_OK) {
435 		uint16 major;
436 		uint16 minor;
437 		uint32 blocksize;
438 		uint32 blocksize2;
439 		uint32 blocks;
440 		uint32 devflags;
441 		uint32 lastacc;
442 		char product[33];
443 		int32 err;
444 
445 		map = XHDrvMap();
446 		dprintf("XDrvMap() 0x%08lx\n", map);
447 		// sadly XDrvmap() has the same issues as XBIOS, it only lists known partitions.
448 		// so we just iterate on each major and try to see if there is something.
449 		for (driveID = 0; driveID < 32; driveID++) {
450 			uint32 startsect;
451 			err = XHInqDev(driveID, &major, &minor, &startsect, NULL);
452 			if (err < 0) {
453 				;//dprintf("XHInqDev(%d) error %d\n", driveID, err);
454 			} else {
455 				dprintf("XHInqDev(%d): (%d,%d):%d\n", driveID, major, minor, startsect);
456 			}
457 		}
458 
459 		product[32] = '\0';
460 		for (major = 0; major < 256; major++) {
461 			if (major == 64) // we don't want floppies
462 				continue;
463 			if (major > 23) // extensions and non-standard stuff... skip for speed.
464 				break;
465 
466 			for (minor = 0; minor < 255; minor++) {
467 				if (minor && (major < 8 || major >15))
468 					break; // minor only used for the SCSI LUN AFAIK.
469 				if (minor > 15) // are more used at all ?
470 					break;
471 
472 				product[0] = '\0';
473 				blocksize = 0;
474 				blocksize2 = 0;
475 #if 0
476 				err = XHLastAccess(major, minor, &lastacc);
477 				if (err < 0) {
478 					;//dprintf("XHLastAccess(%d,%d) error %d\n", major, minor, err);
479 				} else
480 					dprintf("XHLastAccess(%d,%d): %ld\n", major, minor, lastacc);
481 //continue;
482 #endif
483 				// we can pass NULL pointers but just to play safe we don't.
484 				err = XHInqTarget(major, minor, &blocksize, &devflags, product);
485 				if (err < 0) {
486 					dprintf("XHInqTarget(%d,%d) error %d\n", major, minor, err);
487 					continue;
488 				}
489 				err = XHGetCapacity(major, minor, &blocks, &blocksize2);
490 				if (err < 0) {
491 					//dprintf("XHGetCapacity(%d,%d) error %d\n", major, minor, err);
492 					continue;
493 				}
494 
495 				if (blocksize == 0) {
496 					dprintf("XHDI: blocksize for (%d,%d) is 0!\n", major, minor);
497 				}
498 				//dprintf("XHDI: (%d,%d) blocksize1 %ld blocksize2 %ld\n", major, minor, blocksize, blocksize2);
499 
500 				dprintf("XHDI(%d,%d): blksize %d, blocks %d, flags 0x%08lx, '%s'\n", major, minor, blocksize, blocks, devflags, product);
501 				driveID = (uint8)major;
502 
503 				//if (driveID == gBootDriveID)
504 				//	continue;
505 //continue;
506 
507 				BlockHandle *drive = new(nothrow) XHDIDrive(driveID, major, minor);
508 				if (drive->InitCheck() != B_OK) {
509 					dprintf("could not add drive (%d,%d)\n", major, minor);
510 					delete drive;
511 					continue;
512 				}
513 
514 				devicesList->Add(drive);
515 				driveCount++;
516 
517 				if (drive->FillIdentifier() != B_OK)
518 					identifierMissing = true;
519 			}
520 		}
521 	}
522 	if (!driveCount) { // try to fallback to BIOS XXX: use MetaDOS
523 		map = Drvmap();
524 		dprintf("Drvmap(): 0x%08lx\n", map);
525 		for (driveID = 0; driveID < 32; driveID++) {
526 			bool present = map & 0x1;
527 			map >>= 1;
528 			if (!present)
529 				continue;
530 
531 			if (driveID == gBootDriveID)
532 				continue;
533 
534 			BlockHandle *drive = new(nothrow) BlockHandle(driveID);
535 			if (drive->InitCheck() != B_OK) {
536 				dprintf("could not add drive %u\n", driveID);
537 				delete drive;
538 				continue;
539 			}
540 
541 			devicesList->Add(drive);
542 			driveCount++;
543 
544 			if (drive->FillIdentifier() != B_OK)
545 				identifierMissing = true;
546 		}
547 	}
548 	dprintf("number of drives: %d\n", driveCount);
549 
550 	if (identifierMissing) {
551 		// we cannot distinguish between all drives by identifier, we need
552 		// compute checksums for them
553 		find_unique_check_sums(devicesList);
554 	}
555 
556 	sBlockDevicesAdded = true;
557 	return B_OK;
558 }
559 
560 
561 //	#pragma mark -
562 
563 
564 BlockHandle::BlockHandle(int handle)
565 	: Handle(handle)
566 {
567 	TRACE(("BlockHandle::%s(): drive ID %u\n", __FUNCTION__, fHandle));
568 }
569 
570 
571 BlockHandle::~BlockHandle()
572 {
573 }
574 
575 
576 ssize_t
577 BlockHandle::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize)
578 {
579 	ssize_t ret;
580 	uint32 offset = pos % fBlockSize;
581 	pos /= fBlockSize;
582 	TRACE(("BlockHandle::%s: (%d) %Ld, %d\n", __FUNCTION__, fHandle, pos, bufferSize));
583 
584 	uint32 blocksLeft = (bufferSize + offset + fBlockSize - 1) / fBlockSize;
585 	int32 totalBytesRead = 0;
586 
587 	//TRACE(("BIOS reads %lu bytes from %Ld (offset = %lu), drive %u\n",
588 	//	blocksLeft * fBlockSize, pos * fBlockSize, offset, fDriveID));
589 
590 	// read partial block
591 	if (offset) {
592 		ret = ReadBlocks(gScratchBuffer, pos, 1);
593 		if (ret < 0)
594 			return ret;
595 		totalBytesRead += fBlockSize - offset;
596 		memcpy(buffer, gScratchBuffer + offset, totalBytesRead);
597 
598 	}
599 
600 	uint32 scratchSize = SCRATCH_SIZE / fBlockSize;
601 
602 	while (blocksLeft > 0) {
603 		uint32 blocksRead = blocksLeft;
604 		if (blocksRead > scratchSize)
605 			blocksRead = scratchSize;
606 
607 		ret = ReadBlocks(gScratchBuffer, pos, blocksRead);
608 		if (ret < 0)
609 			return ret;
610 
611 		uint32 bytesRead = fBlockSize * blocksRead - offset;
612 		// copy no more than bufferSize bytes
613 		if (bytesRead > bufferSize)
614 			bytesRead = bufferSize;
615 
616 		memcpy(buffer, (void *)(gScratchBuffer + offset), bytesRead);
617 		pos += blocksRead;
618 		offset = 0;
619 		blocksLeft -= blocksRead;
620 		bufferSize -= bytesRead;
621 		buffer = (void *)((addr_t)buffer + bytesRead);
622 		totalBytesRead += bytesRead;
623 	}
624 
625 	return totalBytesRead;
626 }
627 
628 
629 ssize_t
630 BlockHandle::WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize)
631 {
632 	// we don't have to know how to write
633 	return B_NOT_ALLOWED;
634 }
635 
636 
637 ssize_t
638 BlockHandle::ReadBlocks(void *buffer, off_t first, int32 count)
639 {
640 	return B_NOT_ALLOWED;
641 }
642 
643 
644 status_t
645 BlockHandle::FillIdentifier()
646 {
647 	return B_NOT_ALLOWED;
648 }
649 
650 //	#pragma mark -
651 
652 /*
653  * BIOS based disk access.
654  * Only for fallback from missing XHDI.
655  * XXX: This is broken!
656  * XXX: check for physical drives in PUN_INFO
657  * XXX: at least try to use MetaDOS calls instead.
658  */
659 
660 
661 BIOSDrive::BIOSDrive(int handle)
662 	: BlockHandle(handle)
663 {
664 	TRACE(("BIOSDrive::%s(%d)\n", __FUNCTION__, fHandle));
665 
666 	/* first check if the drive exists */
667 	/* note floppy B can be reported present anyway... */
668 	uint32 map = Drvmap();
669 	if (!(map & (1 << fHandle))) {
670 		fSize = 0LL;
671 		return;
672 	}
673 	//XXX: check size
674 
675 	if (get_drive_parameters(fHandle, &fParameters) != B_OK) {
676 		dprintf("getting drive parameters for: %u failed!\n", fHandle);
677 		return;
678 	}
679 	fBlockSize = 512;
680 	fSize = fParameters.sectors * fBlockSize;
681 	fHasParameters = false;
682 
683 #if 0
684 	if (get_ext_drive_parameters(driveID, &fParameters) != B_OK) {
685 		// old style CHS support
686 
687 		if (get_drive_parameters(driveID, &fParameters) != B_OK) {
688 			dprintf("getting drive parameters for: %u failed!\n", fDriveID);
689 			return;
690 		}
691 
692 		TRACE(("  cylinders: %lu, heads: %lu, sectors: %lu, bytes_per_sector: %u\n",
693 			fParameters.cylinders, fParameters.heads, fParameters.sectors_per_track,
694 			fParameters.bytes_per_sector));
695 		TRACE(("  total sectors: %Ld\n", fParameters.sectors));
696 
697 		fBlockSize = 512;
698 		fSize = fParameters.sectors * fBlockSize;
699 		fLBA = false;
700 		fHasParameters = false;
701 	} else {
702 		TRACE(("size: %x\n", fParameters.parameters_size));
703 		TRACE(("drive_path_signature: %x\n", fParameters.device_path_signature));
704 		TRACE(("host bus: \"%s\", interface: \"%s\"\n", fParameters.host_bus,
705 			fParameters.interface_type));
706 		TRACE(("cylinders: %lu, heads: %lu, sectors: %lu, bytes_per_sector: %u\n",
707 			fParameters.cylinders, fParameters.heads, fParameters.sectors_per_track,
708 			fParameters.bytes_per_sector));
709 		TRACE(("total sectors: %Ld\n", fParameters.sectors));
710 
711 		fBlockSize = fParameters.bytes_per_sector;
712 		fSize = fParameters.sectors * fBlockSize;
713 		fLBA = true;
714 		fHasParameters = true;
715 	}
716 #endif
717 }
718 
719 
720 BIOSDrive::~BIOSDrive()
721 {
722 }
723 
724 
725 status_t
726 BIOSDrive::FillIdentifier()
727 {
728 	TRACE(("BIOSDrive::%s: (%d)\n", __FUNCTION__, fHandle));
729 #if 0
730 	if (HasParameters()) {
731 		// try all drive_parameters versions, beginning from the most informative
732 
733 #if 0
734 		if (fill_disk_identifier_v3(fIdentifier, fParameters) == B_OK)
735 			return B_OK;
736 
737 		if (fill_disk_identifier_v2(fIdentifier, fParameters) == B_OK)
738 			return B_OK;
739 #else
740 		// TODO: the above version is the correct one - it's currently
741 		//		disabled, as the kernel boot code only supports the
742 		//		UNKNOWN_BUS/UNKNOWN_DEVICE way to find the correct boot
743 		//		device.
744 		if (fill_disk_identifier_v3(fIdentifier, fParameters) != B_OK)
745 			fill_disk_identifier_v2(fIdentifier, fParameters);
746 
747 #endif
748 
749 		// no interesting information, we have to fall back to the default
750 		// unknown interface/device type identifier
751 	}
752 
753 	fIdentifier.bus_type = UNKNOWN_BUS;
754 	fIdentifier.device_type = UNKNOWN_DEVICE;
755 	fIdentifier.device.unknown.size = Size();
756 
757 	for (int32 i = 0; i < NUM_DISK_CHECK_SUMS; i++) {
758 		fIdentifier.device.unknown.check_sums[i].offset = -1;
759 		fIdentifier.device.unknown.check_sums[i].sum = 0;
760 	}
761 #endif
762 
763 	return B_ERROR;
764 }
765 
766 
767 ssize_t
768 BIOSDrive::ReadBlocks(void *buffer, off_t first, int32 count)
769 {
770 	int sectorsPerBlocks = (fBlockSize / 256);
771 	int32 ret;
772 	TRACE(("BIOSDrive::%s(%Ld,%ld) (%d)\n", __FUNCTION__, first, count, fHandle));
773 	// XXX: check for AHDI 3.0 before using long recno!!!
774 	ret = Rwabs(RW_READ | RW_NOTRANSLATE, buffer, sectorsPerBlocks, -1, fHandle, first * sectorsPerBlocks);
775 	if (ret < 0)
776 		return toserror(ret);
777 	return ret;
778 }
779 
780 
781 //	#pragma mark -
782 
783 /*
784  * XHDI based devices
785  */
786 
787 
788 XHDIDrive::XHDIDrive(int handle, uint16 major, uint16 minor)
789 	: BlockHandle(handle)
790 {
791 	/* first check if the drive exists */
792 	int32 err;
793 	uint32 devflags;
794 	uint32 blocks;
795 	uint32 blocksize;
796 	char product[33];
797 
798 	fMajor = major;
799 	fMinor = minor;
800 	TRACE(("XHDIDrive::%s(%d, %d,%d)\n", __FUNCTION__, handle, fMajor, fMinor));
801 
802 	product[32] = '\0';
803 	err = XHInqTarget(major, minor, &fBlockSize, &devflags, product);
804 	if (err < 0)
805 		return;
806 	//XXX: check size
807 	err = XHGetCapacity(major, minor, &blocks, &blocksize);
808 	if (err < 0)
809 		return;
810 
811 	if (fBlockSize == 0)
812 		fBlockSize = 512;
813 
814 	fSize = blocks * fBlockSize;
815 	fHasParameters = false;
816 #if 0
817 	if (get_drive_parameters(fHandle, &fParameters) != B_OK) {
818 		dprintf("getting drive parameters for: %u failed!\n", fHandle);
819 		return;
820 	}
821 	fBlockSize = 512;
822 	fSize = fParameters.sectors * fBlockSize;
823 	fHasParameters = false;
824 #endif
825 #if 0
826 	if (get_ext_drive_parameters(driveID, &fParameters) != B_OK) {
827 		// old style CHS support
828 
829 		if (get_drive_parameters(driveID, &fParameters) != B_OK) {
830 			dprintf("getting drive parameters for: %u failed!\n", fDriveID);
831 			return;
832 		}
833 
834 		TRACE(("  cylinders: %lu, heads: %lu, sectors: %lu, bytes_per_sector: %u\n",
835 			fParameters.cylinders, fParameters.heads, fParameters.sectors_per_track,
836 			fParameters.bytes_per_sector));
837 		TRACE(("  total sectors: %Ld\n", fParameters.sectors));
838 
839 		fBlockSize = 512;
840 		fSize = fParameters.sectors * fBlockSize;
841 		fLBA = false;
842 		fHasParameters = false;
843 	} else {
844 		TRACE(("size: %x\n", fParameters.parameters_size));
845 		TRACE(("drive_path_signature: %x\n", fParameters.device_path_signature));
846 		TRACE(("host bus: \"%s\", interface: \"%s\"\n", fParameters.host_bus,
847 			fParameters.interface_type));
848 		TRACE(("cylinders: %lu, heads: %lu, sectors: %lu, bytes_per_sector: %u\n",
849 			fParameters.cylinders, fParameters.heads, fParameters.sectors_per_track,
850 			fParameters.bytes_per_sector));
851 		TRACE(("total sectors: %Ld\n", fParameters.sectors));
852 
853 		fBlockSize = fParameters.bytes_per_sector;
854 		fSize = fParameters.sectors * fBlockSize;
855 		fLBA = true;
856 		fHasParameters = true;
857 	}
858 #endif
859 }
860 
861 
862 XHDIDrive::~XHDIDrive()
863 {
864 }
865 
866 
867 status_t
868 XHDIDrive::FillIdentifier()
869 {
870 	TRACE(("XHDIDrive::%s: (%d,%d)\n", __FUNCTION__, fMajor, fMinor));
871 
872 	fIdentifier.bus_type = UNKNOWN_BUS;
873 	fIdentifier.device_type = UNKNOWN_DEVICE;
874 	fIdentifier.device.unknown.size = Size();
875 #if 0
876 	// cf. http://toshyp.atari.org/010008.htm#XHDI-Terminologie
877 	if (fMajor >= 8 && fMajor <= 15) { // scsi
878 		fIdentifier.device_type = SCSI_DEVICE;
879 		fIdentifier.device.scsi.logical_unit = fMinor;
880 		//XXX: where am I supposed to put the ID ???
881 	}
882 #endif
883 
884 	for (int32 i = 0; i < NUM_DISK_CHECK_SUMS; i++) {
885 		fIdentifier.device.unknown.check_sums[i].offset = -1;
886 		fIdentifier.device.unknown.check_sums[i].sum = 0;
887 	}
888 
889 	return B_ERROR;
890 }
891 
892 
893 ssize_t
894 XHDIDrive::ReadBlocks(void *buffer, off_t first, int32 count)
895 {
896 	int sectorsPerBlocks = (fBlockSize / 256);
897 	int32 ret;
898 	uint16 flags = RW_READ;
899 	TRACE(("XHDIDrive::%s(%Ld, %d) (%d,%d)\n", __FUNCTION__, first, count, fMajor, fMinor));
900 	ret = XHReadWrite(fMajor, fMinor, flags, (uint32)first, (uint16)count, buffer);
901 	if (ret < 0)
902 		return xhdierror(ret);
903 	//TRACE(("XHReadWrite: %ld\n", ret));
904 	/*
905 	uint8 *b = (uint8 *)buffer;
906 	int i = 0;
907 	for (i = 0; i < 512; i+=16) {
908 		TRACE(("[%8Ld+%3ld] %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
909 			first, i, b[i], b[i+1], b[i+2], b[i+3], b[i+4], b[i+5], b[i+6], b[i+7],
910 			b[i+8], b[i+9], b[i+10], b[i+11], b[i+12], b[i+13], b[i+14], b[i+15]));
911 		//break;
912 	}
913 	*/
914 	return ret;
915 }
916 
917 
918 
919 
920 //	#pragma mark -
921 
922 
923 status_t
924 platform_add_boot_device(struct stage2_args *args, NodeList *devicesList)
925 {
926 	TRACE(("boot drive ID: %x\n", gBootDriveID));
927 	init_xhdi();
928 
929 	//XXX: FIXME
930 	BlockHandle *drive = new(nothrow) BlockHandle(gBootDriveID);
931 	if (drive->InitCheck() != B_OK) {
932 		dprintf("no boot drive!\n");
933 		return B_ERROR;
934 	}
935 
936 	devicesList->Add(drive);
937 
938 	if (drive->FillIdentifier() != B_OK) {
939 		// We need to add all block devices to give the kernel the possibility
940 		// to find the right boot volume
941 		add_block_devices(devicesList, true);
942 	}
943 
944 	TRACE(("boot drive size: %Ld bytes\n", drive->Size()));
945 	gKernelArgs.boot_volume.SetInt32(BOOT_VOLUME_BOOTED_FROM_IMAGE,
946 		gBootedFromImage);
947 
948 	return B_OK;
949 }
950 
951 
952 status_t
953 platform_get_boot_partition(struct stage2_args *args, Node *bootDevice,
954 	NodeList *list, boot::Partition **_partition)
955 {
956 	BlockHandle *drive = static_cast<BlockHandle *>(bootDevice);
957 	off_t offset = (off_t)gBootPartitionOffset * drive->BlockSize();
958 
959 	dprintf("boot partition offset: %Ld\n", offset);
960 
961 	NodeIterator iterator = list->GetIterator();
962 	boot::Partition *partition = NULL;
963 	while ((partition = (boot::Partition *)iterator.Next()) != NULL) {
964 		TRACE(("partition offset = %Ld, size = %Ld\n", partition->offset, partition->size));
965 		// search for the partition that contains the partition
966 		// offset as reported by the BFS boot block
967 		if (offset >= partition->offset
968 			&& offset < partition->offset + partition->size) {
969 			*_partition = partition;
970 			return B_OK;
971 		}
972 	}
973 
974 	return B_ENTRY_NOT_FOUND;
975 }
976 
977 
978 status_t
979 platform_add_block_devices(stage2_args *args, NodeList *devicesList)
980 {
981 	init_xhdi();
982 	return add_block_devices(devicesList, false);
983 }
984 
985 
986 status_t
987 platform_register_boot_device(Node *device)
988 {
989 	BlockHandle *drive = (BlockHandle *)device;
990 
991 #if 0
992 	check_cd_boot(drive);
993 #endif
994 
995 	gKernelArgs.boot_volume.SetInt64("boot drive number", drive->DriveID());
996 	gKernelArgs.boot_volume.SetData(BOOT_VOLUME_DISK_IDENTIFIER, B_RAW_TYPE,
997 		&drive->Identifier(), sizeof(disk_identifier));
998 
999 	return B_OK;
1000 }
1001 
1002