Add LBA48 support

This commit is contained in:
Matt Harlum 2023-12-16 18:10:32 +00:00 committed by Matt Harlum
parent 79193bd356
commit d2e7843bc0
4 changed files with 76 additions and 13 deletions

View File

@ -13,7 +13,7 @@
## Features
* Autoboot
* Works with Kickstart 1.3 and up
* Supports up to 127GB drives
* Supports up to 2TB drives
* Supports ATAPI Devices (CD/DVD-ROM, Zip disk etc)
* Boot from ZIP/LS-120 etc
* [Boot from CD-ROM*](#boot-from-cdrom)

66
ata.c
View File

@ -23,6 +23,7 @@
#include "wait.h"
static BYTE write_taskfile_lba(struct IDEUnit *unit, UBYTE command, ULONG lba, UBYTE sectorCount);
static BYTE write_taskfile_lba48(struct IDEUnit *unit, UBYTE command, ULONG lba, UBYTE sectorCount);
static BYTE write_taskfile_chs(struct IDEUnit *unit, UBYTE command, ULONG lba, UBYTE sectorCount);
/**
@ -309,9 +310,25 @@ bool ata_init_unit(struct IDEUnit *unit) {
unit->multiple_count = 1;
}
if (unit->lba == true) {
// Support LBA-48 but only up to 2TB
if (((*((UWORD *)buf + ata_identify_features) & ata_feature_lba48) != 0) && unit->logicalSectors >= 0xFFFFFFF) {
if (*((UWORD *)buf + ata_identify_lba48_sectors + 2) > 0 ||
*((UWORD *)buf + ata_identify_lba48_sectors + 3) > 0) {
Info("INIT: Rejecting drive larger than 2TB\n");
return false;
}
unit->lba48 = true;
Info("INIT: Drive supports LBA48 mode \n");
unit->logicalSectors = (*((UWORD *)buf + ata_identify_lba48_sectors + 1) << 16 | *((UWORD *)buf + ata_identify_lba48_sectors));
unit->write_taskfile = &write_taskfile_lba48;
} else if (unit->lba == true) {
// LBA-28 up to 127GB
unit->write_taskfile = &write_taskfile_lba;
} else {
// CHS Mode
Warn("INIT: Drive doesn't support LBA mode\n");
unit->write_taskfile = &write_taskfile_chs;
unit->logicalSectors = (unit->cylinders * unit->heads * unit->sectorsPerTrack);
@ -321,7 +338,12 @@ bool ata_init_unit(struct IDEUnit *unit) {
if (unit->logicalSectors == 0 || unit->heads == 0 || unit->cylinders == 0) goto ident_failed;
if (unit->logicalSectors >= 16514064) {
if (unit->logicalSectors >= 267382800) {
// For drives larger than 127GB fudge the geometry
unit->heads = 63;
unit->sectorsPerTrack = 255;
unit->cylinders = (unit->logicalSectors / (63*255));
} else if (unit->logicalSectors >= 16514064) {
// If a drive is larger than 8GB then the drive will report a geometry of 16383/16/63 (CHS)
// In this case generate a new Cylinders value
unit->heads = 16;
@ -422,7 +444,13 @@ BYTE ata_read(void *buffer, ULONG lba, ULONG count, ULONG *actual, struct IDEUni
UBYTE error = 0;
ULONG txn_count; // Amount of sectors to transfer in the current READ/WRITE command
UBYTE command = (unit->xfer_multiple) ? ATA_CMD_READ_MULTIPLE : ATA_CMD_READ;
UBYTE command;
if (unit->lba48) {
command = ATA_CMD_READ_MULTIPLE_EXT;
} else {
command = (unit->xfer_multiple) ? ATA_CMD_READ_MULTIPLE : ATA_CMD_READ;
}
if (count == 0) return TDERR_TooFewSecs;
@ -517,7 +545,13 @@ BYTE ata_write(void *buffer, ULONG lba, ULONG count, ULONG *actual, struct IDEUn
ULONG txn_count; // Amount of sectors to transfer in the current READ/WRITE command
UBYTE command = (unit->xfer_multiple) ? ATA_CMD_WRITE_MULTIPLE : ATA_CMD_WRITE;
UBYTE command;
if (unit->lba48) {
command = ATA_CMD_WRITE_MULTIPLE_EXT;
} else {
command = (unit->xfer_multiple) ? ATA_CMD_WRITE_MULTIPLE : ATA_CMD_WRITE;
}
if (count == 0) return TDERR_TooFewSecs;
@ -680,3 +714,27 @@ static BYTE write_taskfile_lba(struct IDEUnit *unit, UBYTE command, ULONG lba, U
return 0;
}
/**
* write_taskfile_lba48
*
* @param unit Pointer to an IDEUnit struct
* @param lba Pointer to the LBA variable
*/
static BYTE write_taskfile_lba48(struct IDEUnit *unit, UBYTE command, ULONG lba, UBYTE sectorCount) {
if (!ata_wait_ready(unit,ATA_RDY_WAIT_COUNT))
return HFERR_SelTimeout;
*unit->drive->sectorCount = (sectorCount == 0) ? 1 : 0;
*unit->drive->lbaHigh = 0;
*unit->drive->lbaMid = 0;
*unit->drive->lbaLow = (UBYTE)(lba >> 24);
*unit->drive->sectorCount = sectorCount; // Count value of 0 indicates to transfer 256 sectors
*unit->drive->lbaHigh = (UBYTE)(lba >> 16);
*unit->drive->lbaMid = (UBYTE)(lba >> 8);
*unit->drive->lbaLow = (UBYTE)(lba);
*unit->drive->status_command = command;
return 0;
}

20
ata.h
View File

@ -41,13 +41,15 @@
#define ata_err_flag_aborted (1<<2)
#define ATA_CMD_DEVICE_RESET 0x08
#define ATA_CMD_IDENTIFY 0xEC
#define ATA_CMD_READ 0x20
#define ATA_CMD_READ_MULTIPLE 0xC4
#define ATA_CMD_WRITE 0x30
#define ATA_CMD_WRITE_MULTIPLE 0xC5
#define ATA_CMD_SET_MULTIPLE 0xC6
#define ATA_CMD_DEVICE_RESET 0x08
#define ATA_CMD_IDENTIFY 0xEC
#define ATA_CMD_READ 0x20
#define ATA_CMD_READ_MULTIPLE 0xC4
#define ATA_CMD_READ_MULTIPLE_EXT 0x29
#define ATA_CMD_WRITE 0x30
#define ATA_CMD_WRITE_MULTIPLE 0xC5
#define ATA_CMD_WRITE_MULTIPLE_EXT 0x39
#define ATA_CMD_SET_MULTIPLE 0xC6
// Identify data word offsets
#define ata_identify_cylinders 1
@ -60,11 +62,13 @@
#define ata_identify_capabilities 49
#define ata_identify_logical_sectors 60
#define ata_identify_pio_modes 64
#define ata_identify_features 83
#define ata_identify_lba48_sectors 100
#define ataf_multiple (1<<8)
#define ata_capability_lba (1<<9)
#define ata_capability_dma (1<<8)
#define ata_feature_lba48 (1<<10)
enum xfer_dir {
READ,

View File

@ -64,6 +64,7 @@ struct IDEUnit {
BOOL mediumPresentPrev;
BOOL xfer_multiple;
BOOL lba;
BOOL lba48;
UWORD open_count;
UWORD change_count;
UWORD cylinders;