Remove 2TB limit, support full LBA-48 range

This commit is contained in:
Matt Harlum 2025-10-22 00:39:38 +00:00
parent 27abd230db
commit 5124c1c830
8 changed files with 123 additions and 40 deletions

38
ata.c
View File

@ -21,9 +21,9 @@
#include "sleep.h"
#include "lide_alib.h"
static BYTE write_taskfile_lba(struct IDEUnit *unit, UBYTE command, ULONG lba, UBYTE sectorCount, UBYTE features);
static BYTE write_taskfile_lba48(struct IDEUnit *unit, UBYTE command, ULONG lba, UBYTE sectorCount, UBYTE features);
static BYTE write_taskfile_chs(struct IDEUnit *unit, UBYTE command, ULONG lba, UBYTE sectorCount, UBYTE features);
static BYTE write_taskfile_lba(struct IDEUnit *unit, UBYTE command, unsigned long long lba, UBYTE sectorCount, UBYTE features);
static BYTE write_taskfile_lba48(struct IDEUnit *unit, UBYTE command, unsigned long long, UBYTE sectorCount, UBYTE features);
static BYTE write_taskfile_chs(struct IDEUnit *unit, UBYTE command, unsigned long long lba, UBYTE sectorCount, UBYTE features);
/**
* ata_status_reg_delay
@ -412,16 +412,14 @@ bool ata_init_unit(struct IDEUnit *unit, void *base) {
// Support LBA-48 but only up to 2TB
if ((buf[ata_identify_features] & ata_feature_lba48) && unit->logicalSectors >= 0xFFFFFFF) {
if (buf[ata_identify_lba48_sectors + 2] > 0 ||
buf[ata_identify_lba48_sectors + 3] > 0) {
Info("INIT: Rejecting drive larger than 2TB\n");
goto ident_failed;
}
unit->flags.lba48 = true;
Info("INIT: Drive supports LBA48 mode \n");
unit->logicalSectors = (buf[ata_identify_lba48_sectors + 1] << 16 |
buf[ata_identify_lba48_sectors]);
Info("INIT: Large drive, using LBA48 mode \n");
unit->logicalSectors = 0;
unit->logicalSectors |= ((unsigned long long)buf[ata_identify_lba48_sectors]) << 0;
unit->logicalSectors |= ((unsigned long long)buf[ata_identify_lba48_sectors+1]) << 16;
unit->logicalSectors |= ((unsigned long long)buf[ata_identify_lba48_sectors+2]) << 32;
unit->write_taskfile = &write_taskfile_lba48;
} else if (unit->flags.lba == true) {
@ -483,7 +481,7 @@ ident_failed:
Info("INIT: Blockshift: %ld\n",unit->blockShift);
unit->flags.present = true;
Info("INIT: LBAs %ld Blocksize: %ld\n",unit->logicalSectors,unit->blockSize);
Info("INIT: LBAs %lld Blocksize: %ld\n",unit->logicalSectors,unit->blockSize);
if (buf) FreeMem(buf,512);
return true;
@ -539,7 +537,7 @@ bool ata_set_multiple(struct IDEUnit *unit, BYTE multiple) {
* @param unit Pointer to the unit structure
* @returns error
*/
BYTE ata_read(void *buffer, ULONG lba, ULONG count, struct IDEUnit *unit) {
BYTE ata_read(void *buffer, unsigned long long lba, ULONG count, struct IDEUnit *unit) {
Trace("ata_read enter\n");
Trace("ATA: Request sector count: %ld\n",count);
@ -627,7 +625,7 @@ BYTE ata_read(void *buffer, ULONG lba, ULONG count, struct IDEUnit *unit) {
* @param unit Pointer to the unit structure
* @returns error
*/
BYTE ata_write(void *buffer, ULONG lba, ULONG count, struct IDEUnit *unit) {
BYTE ata_write(void *buffer, unsigned long long lba, ULONG count, struct IDEUnit *unit) {
Trace("ata_write enter\n");
Trace("ATA: Request sector count: %ld\n",count);
@ -748,7 +746,7 @@ void ata_write_unaligned_long(void *source asm("a0"), void *destination asm("a1"
* @param unit Pointer to an IDEUnit struct
* @param lba Pointer to the LBA variable
*/
static BYTE write_taskfile_chs(struct IDEUnit *unit, UBYTE command, ULONG lba, UBYTE sectorCount, UBYTE features) {
static BYTE write_taskfile_chs(struct IDEUnit *unit, UBYTE command, unsigned long long lba, UBYTE sectorCount, UBYTE features) {
UWORD cylinder = (lba / (unit->heads * unit->sectorsPerTrack));
UBYTE head = ((lba / unit->sectorsPerTrack) % unit->heads) & 0xF;
UBYTE sector = (lba % unit->sectorsPerTrack) + 1;
@ -778,7 +776,7 @@ static BYTE write_taskfile_chs(struct IDEUnit *unit, UBYTE command, ULONG lba, U
* @param unit Pointer to an IDEUnit struct
* @param lba Pointer to the LBA variable
*/
static BYTE write_taskfile_lba(struct IDEUnit *unit, UBYTE command, ULONG lba, UBYTE sectorCount, UBYTE features) {
static BYTE write_taskfile_lba(struct IDEUnit *unit, UBYTE command, unsigned long long lba, UBYTE sectorCount, UBYTE features) {
BYTE devHead;
if (!ata_wait_ready(unit,ATA_RDY_WAIT_COUNT))
@ -804,14 +802,14 @@ static BYTE write_taskfile_lba(struct IDEUnit *unit, UBYTE command, ULONG lba, U
* @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, UBYTE features) {
static BYTE write_taskfile_lba48(struct IDEUnit *unit, UBYTE command, unsigned long long lba, UBYTE sectorCount, UBYTE features) {
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.lbaHigh = (UBYTE)(lba >> 40);
*unit->drive.lbaMid = (UBYTE)(lba >> 32);
*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);
@ -828,7 +826,7 @@ static BYTE write_taskfile_lba48(struct IDEUnit *unit, UBYTE command, ULONG lba,
/**
* ata_set_pio
*
* @param unit Pointer t oan IDEUnit struct
* @param unit Pointer to an IDEUnit struct
* @param pio pio mode
*/
BYTE ata_set_pio(struct IDEUnit *unit, UBYTE pio) {

4
ata.h
View File

@ -110,8 +110,8 @@ bool ata_identify(struct IDEUnit *, UWORD *);
bool ata_set_multiple(struct IDEUnit *unit, BYTE multiple);
void ata_set_xfer(struct IDEUnit *unit, enum xfer method);
BYTE ata_read(void *buffer, ULONG lba, ULONG count, struct IDEUnit *unit);
BYTE ata_write(void *buffer, ULONG lba, ULONG count, struct IDEUnit *unit);
BYTE ata_read(void *buffer, unsigned long long lba, ULONG count, struct IDEUnit *unit);
BYTE ata_write(void *buffer, unsigned long long lba, ULONG count, struct IDEUnit *unit);
BYTE ata_set_pio(struct IDEUnit *unit, UBYTE pio);
BYTE scsi_ata_passthrough( struct IDEUnit *unit, struct SCSICmd *cmd);

View File

@ -15,6 +15,7 @@
#include <string.h>
#include <stdio.h>
#include <limits.h>
#include "ata.h"
#include "atapi.h"
@ -610,8 +611,13 @@ static void td_get_geometry(struct IOStdReq *ioreq) {
// Clear the geometry struct beforehand to make sure reserved / unused parts are zero
memset(geometry,0,sizeof(struct DriveGeometry));
if (unit->logicalSectors > ULONG_MAX) {
geometry->dg_TotalSectors = ULONG_MAX;
} else {
geometry->dg_TotalSectors = unit->logicalSectors;
}
geometry->dg_SectorSize = unit->blockSize;
geometry->dg_TotalSectors = unit->logicalSectors;
geometry->dg_Cylinders = unit->cylinders;
geometry->dg_CylSectors = (unit->sectorsPerTrack * unit->heads);
geometry->dg_Heads = unit->heads;

View File

@ -47,7 +47,7 @@ struct IDEUnit {
struct ExecBase *SysBase;
struct IOTask *itask;
struct Drive drive;
BYTE (*write_taskfile)(struct IDEUnit *, UBYTE, ULONG, UBYTE, UBYTE);
BYTE (*write_taskfile)(struct IDEUnit *, UBYTE, unsigned long long, UBYTE, UBYTE);
enum xfer xferMethod;
ata_xfer_func read_fast;
ata_xfer_func write_fast;
@ -65,7 +65,7 @@ struct IDEUnit {
UWORD blockSize;
UWORD blockShift;
ULONG cylinders;
ULONG logicalSectors;
unsigned long long logicalSectors;
struct MinList changeInts;
UBYTE multipleCount;
struct {

View File

@ -111,7 +111,7 @@ static BYTE handle_scsi_command(struct IOStdReq *ioreq) {
UBYTE *data = (APTR)scsi_command->scsi_Data;
UBYTE *command = (APTR)scsi_command->scsi_Command;
ULONG lba;
unsigned long long lba;
ULONG count;
BYTE error = 0;
scsi_command->scsi_SenseActual = 0;
@ -144,7 +144,11 @@ static BYTE handle_scsi_command(struct IOStdReq *ioreq) {
break;
case SCSI_CMD_READ_CAPACITY_10:
error = scsi_read_capacity_emu(unit,scsi_command);
error = scsi_read_capacity_10_emu(unit,scsi_command);
break;
case SCSI_CMD_READ_CAPACITY_16:
error = scsi_read_capacity_16_emu(unit,scsi_command);
break;
case SCSI_CMD_READ_6:
@ -158,8 +162,14 @@ static BYTE handle_scsi_command(struct IOStdReq *ioreq) {
case SCSI_CMD_READ_10:
case SCSI_CMD_WRITE_10:
lba = ((struct SCSI_CDB_10 *)command)->lba;
count = ((struct SCSI_CDB_10 *)command)->length;
lba = ((struct SCSI_CDB_10 *)command)->lba;
count = ((struct SCSI_CDB_10 *)command)->length;
goto do_scsi_transfer;
case SCSI_CMD_READ_16:
case SCSI_CMD_WRITE_16:
lba = ((struct SCSI_CDB_16 *)command)->lba;
count = ((struct SCSI_CDB_16 *)command)->length;
do_scsi_transfer:
if (data == NULL || (lba + count) >= unit->logicalSectors) {
@ -373,7 +383,7 @@ static void process_ioreq(struct IOTask *itask, struct IOStdReq *ioreq) {
struct IOExtTD *iotd;
struct IDEUnit *unit;
UWORD blockShift;
long long lba;
unsigned long long lba;
ULONG count;
BYTE error = 0;
enum xfer_dir direction = WRITE;
@ -473,7 +483,7 @@ transfer:
}
blockShift = ((struct IDEUnit *)ioreq->io_Unit)->blockShift;
lba = (((long long)ioreq->io_Actual << 32 | ioreq->io_Offset) >> blockShift);
lba = (((unsigned long long)ioreq->io_Actual << 32 | ioreq->io_Offset) >> blockShift);
count = (ioreq->io_Length >> blockShift);
if (count == 0) {
@ -491,9 +501,9 @@ transfer:
error = atapi_translate(ioreq->io_Data, (ULONG)lba, count, &ioreq->io_Actual, unit, direction);
} else {
if (direction == READ) {
error = ata_read(ioreq->io_Data, (ULONG)lba, count, unit);
error = ata_read(ioreq->io_Data, lba, count, unit);
} else {
error = ata_write(ioreq->io_Data, (ULONG)lba, count, unit);
error = ata_write(ioreq->io_Data, lba, count, unit);
}
ioreq->io_Actual = ioreq->io_Length;
}

View File

@ -169,7 +169,7 @@ static void DumpUnit(struct IOStdReq *req) {
printf("Supports LBA: %s\n", (unit->flags.lba) ? "Yes" : "No");
printf("Supports LBA48: %s\n", (unit->flags.lba48) ? "Yes" : "No");
printf("C/H/S: %d/%d/%d\n", unit->cylinders, unit->heads, unit->sectorsPerTrack);
printf("Logical Sectors: %ld\n", (long int)unit->logicalSectors);
printf("Logical Sectors: %llu\n", (unsigned long long)unit->logicalSectors);
printf("READ/WRITE Multiple: %s\n", (unit->flags.xferMultiple) ? "Yes" : "No");
printf("Multiple count: %d\n", unit->multipleCount);
printf("Last Error: ");

52
scsi.c
View File

@ -8,6 +8,7 @@
#include <proto/alib.h>
#include <proto/exec.h>
#include <string.h>
#include <limits.h>
#include "ata.h"
#include "debug.h"
@ -16,7 +17,6 @@
#include "newstyle.h"
#include "scsi.h"
#include "td64.h"
/**
* fake_scsi_sense
*
@ -166,14 +166,14 @@ BYTE scsi_inquiry_emu(struct IDEUnit *unit, struct SCSICmd *scsi_command) {
}
/**
* scsi_read_capacity_emu
* scsi_read_capacity_10_emu
*
* Emulate SCSI-Direct READ CAPACITY command
* Emulate SCSI-Direct READ CAPACITY (10) command
*
* @param unit Pointer to an IDEUnit struct
* @param scsi_command Pointer to a SCSICmd struct
*/
BYTE scsi_read_capacity_emu(struct IDEUnit *unit, struct SCSICmd *scsi_command) {
BYTE scsi_read_capacity_10_emu(struct IDEUnit *unit, struct SCSICmd *scsi_command) {
struct SCSI_CAPACITY_10 *data = (struct SCSI_CAPACITY_10 *)scsi_command->scsi_Data;
BYTE error;
@ -187,6 +187,49 @@ BYTE scsi_read_capacity_emu(struct IDEUnit *unit, struct SCSICmd *scsi_command)
data->block_size = unit->blockSize;
if (unit->logicalSectors < ULONG_MAX) {
if (cdb->flags & 0x01) {
// Partial Medium Indicator - Return end of cylinder
// Implement this so HDToolbox stops moaning about track size
ULONG spc = unit->sectorsPerTrack * unit->heads;
data->lba = (((cdb->lba / spc) + 1) * spc) - 1;
} else {
data->lba = (unit->logicalSectors) - 1;
}
} else {
data->lba = ULONG_MAX;
}
scsi_command->scsi_Actual = 8;
return 0;
}
/**
* scsi_read_capacity_16_emu
*
* Emulate SCSI-Direct READ CAPACITY (16) command
*
* @param unit Pointer to an IDEUnit struct
* @param scsi_command Pointer to a SCSICmd struct
*/
BYTE scsi_read_capacity_16_emu(struct IDEUnit *unit, struct SCSICmd *scsi_command) {
struct SCSI_CAPACITY_16 *data = (struct SCSI_CAPACITY_16 *)scsi_command->scsi_Data;
BYTE error;
if (data == NULL) {
error = IOERR_BADADDRESS;
fake_scsi_sense(scsi_command,0,0,error);
return error;
}
struct SCSI_READ_CAPACITY_16 *cdb = (struct SCSI_READ_CAPACITY_16 *)scsi_command->scsi_Command;
data->block_size = unit->blockSize;
if (cdb->flags & 0x01) {
// Partial Medium Indicator - Return end of cylinder
// Implement this so HDToolbox stops moaning about track size
@ -196,7 +239,6 @@ BYTE scsi_read_capacity_emu(struct IDEUnit *unit, struct SCSICmd *scsi_command)
data->lba = (unit->logicalSectors) - 1;
}
scsi_command->scsi_Actual = 8;
return 0;

29
scsi.h
View File

@ -26,6 +26,9 @@
#define SCSI_CMD_MODE_SENSE_10 0x5A
#define SCSI_CMD_CLOSE_TRACK_SESS 0x5B
#define SCSI_CMD_START_STOP_UNIT 0x1B
#define SCSI_CMD_READ_16 0x88
#define SCSI_CMD_WRITE_16 0x8A
#define SCSI_CMD_READ_CAPACITY_16 0x9E
#define SCSI_CMD_BLANK 0xA1
#define SCSI_CMD_ATA_PASSTHROUGH 0xA1
#define SCSI_CHECK_CONDITION 0x02
@ -68,6 +71,15 @@ struct __attribute__((packed)) SCSI_CDB_10 {
UBYTE control;
};
struct __attribute__((packed)) SCSI_CDB_16 {
UBYTE operation;
UBYTE flags;
unsigned long long lba;
ULONG length;
UBYTE group;
UBYTE control;
};
struct __attribute__((packed)) SCSI_READ_CAPACITY_10 {
UBYTE operation;
UBYTE reserved1;
@ -76,12 +88,26 @@ struct __attribute__((packed)) SCSI_READ_CAPACITY_10 {
UBYTE flags;
UBYTE control;
};
struct __attribute__((packed)) SCSI_READ_CAPACITY_16 {
UBYTE operation;
UBYTE serviceAction;
unsigned long long lba;
ULONG allocation;
UBYTE flags;
UBYTE control;
};
struct __attribute__((packed)) SCSI_CAPACITY_10 {
ULONG lba;
ULONG block_size;
};
struct __attribute__((packed)) SCSI_CAPACITY_16 {
unsigned long long lba;
ULONG block_size;
char reserved[3];
};
struct __attribute__((packed)) SCSI_FIXED_SENSE {
UBYTE response;
UBYTE pad;
@ -145,7 +171,8 @@ void fake_scsi_sense(struct SCSICmd* command, ULONG info, ULONG specific, BYTE e
struct SCSICmd * MakeSCSICmd(ULONG cdbSize);
void DeleteSCSICmd(struct SCSICmd *cmd);
BYTE scsi_inquiry_emu(struct IDEUnit *unit, struct SCSICmd *scsi_command);
BYTE scsi_read_capacity_emu(struct IDEUnit *unit, struct SCSICmd *scsi_command);
BYTE scsi_read_capacity_10_emu(struct IDEUnit *unit, struct SCSICmd *scsi_command);
BYTE scsi_read_capacity_16_emu(struct IDEUnit *unit, struct SCSICmd *scsi_command);
BYTE scsi_mode_sense_emu(struct IDEUnit *unit, struct SCSICmd *scsi_command);
#endif