Commit 4b3236af authored by Robert Sprowson's avatar Robert Sprowson
Browse files

Run time detect the sector size

Read the sector size from ATA Identify, and keep it in the drive structure. This allows a mix of sector sizes to be used across discs.
Search & replace LOG2_SECTOR_SIZE and SECTOR_SIZE with the value read from the drive.

Tested on Titanium with an assortment of manufacturer drives, capacities, and sector sizes.

Version 4.03. Tagged as 'ADFS-4_03'
parent e1cf30a1
/* (4.02)
/* (4.03)
*
* This file is automatically maintained by srccommit, do not edit manually.
* Last processed by srccommit version: 1.1.
*
*/
#define Module_MajorVersion_CMHG 4.02
#define Module_MajorVersion_CMHG 4.03
#define Module_MinorVersion_CMHG
#define Module_Date_CMHG 24 Mar 2016
#define Module_Date_CMHG 16 Jun 2017
#define Module_MajorVersion "4.02"
#define Module_Version 402
#define Module_MajorVersion "4.03"
#define Module_Version 403
#define Module_MinorVersion ""
#define Module_Date "24 Mar 2016"
#define Module_Date "16 Jun 2017"
#define Module_ApplicationDate "24-Mar-16"
#define Module_ApplicationDate "16-Jun-17"
#define Module_ComponentName "ADFS"
#define Module_ComponentPath "cddl/RiscOS/Sources/FileSys/ADFS/ADFS"
#define Module_FullVersion "4.02"
#define Module_HelpVersion "4.02 (24 Mar 2016)"
#define Module_LibraryVersionInfo "4:2"
#define Module_FullVersion "4.03"
#define Module_HelpVersion "4.03 (16 Jun 2017)"
#define Module_LibraryVersionInfo "4:3"
......@@ -114,14 +114,14 @@ static low_level_error_t transfer_with_retries(uint32_t reason,
{ ATACOMMAND_WRITE_SECTORS_EXT, ATACOMMAND_WRITE_DMA_EXT, }, },
};
ataop_param_lba48_t p = {
.sector_count0 = (uint8_t) (*transfer_length >> LOG2_SECTOR_SIZE),
.sector_count1 = (uint8_t) (*transfer_length >> (LOG2_SECTOR_SIZE + 8)),
.lba0 = (uint8_t) (*disc_address >> LOG2_SECTOR_SIZE),
.lba1 = (uint8_t) (*disc_address >> (LOG2_SECTOR_SIZE + 8)),
.lba2 = (uint8_t) (*disc_address >> (LOG2_SECTOR_SIZE + 16)),
.lba3 = (uint8_t) (*disc_address >> (LOG2_SECTOR_SIZE + 24)),
.lba4 = (uint8_t) (*disc_address >> (LOG2_SECTOR_SIZE + 32)),
.lba5 = (uint8_t) (*disc_address >> (LOG2_SECTOR_SIZE + 36)),
.sector_count0 = (uint8_t) (*transfer_length >> dr->log2_sector_size),
.sector_count1 = (uint8_t) (*transfer_length >> (dr->log2_sector_size + 8)),
.lba0 = (uint8_t) (*disc_address >> dr->log2_sector_size),
.lba1 = (uint8_t) (*disc_address >> (dr->log2_sector_size + 8)),
.lba2 = (uint8_t) (*disc_address >> (dr->log2_sector_size + 16)),
.lba3 = (uint8_t) (*disc_address >> (dr->log2_sector_size + 24)),
.lba4 = (uint8_t) (*disc_address >> (dr->log2_sector_size + 32)),
.lba5 = (uint8_t) (*disc_address >> (dr->log2_sector_size + 36)),
.device = DEVICE_MAGIC | DEVICE_LBA,
.command = command[reason][dr->lba48][1]
};
......@@ -129,7 +129,7 @@ static low_level_error_t transfer_with_retries(uint32_t reason,
{
p.sector_count1 = 0;
p.lba3 = 0;
p.device |= (uint8_t) (*disc_address >> (LOG2_SECTOR_SIZE + 24)) & 0xF;
p.device |= (uint8_t) (*disc_address >> (dr->log2_sector_size + 24)) & 0xF;
}
flags |= ATAOp_DMA |
(dr->deviceid << ATAOp_DeviceIDShift) |
......@@ -212,7 +212,7 @@ static low_level_error_t buffered_transfer(uint32_t reason,
/* First read the existing contents of the disc */
uint64_t buffer_disc_address = *disc_address;
uint8_t *buffer = dr->block_buffer;
size_t remaining = SECTOR_SIZE;
size_t remaining = dr->sector_size;
e = transfer_with_retries(DiscOp_ReadSecs,
flags &~ ATAOp_Scatter,
dr,
......@@ -243,7 +243,7 @@ static low_level_error_t buffered_transfer(uint32_t reason,
/* Do the main transfer */
uint64_t buffer_disc_address = *disc_address;
uint8_t *buffer = dr->block_buffer;
size_t remaining = SECTOR_SIZE;
size_t remaining = dr->sector_size;
e = transfer_with_retries(reason,
flags &~ ATAOp_Scatter,
dr,
......@@ -301,10 +301,10 @@ low_level_error_t discop(uint32_t reason,
goto exit;
}
if (*disc_address + *fg_length > dr->capacity || !IS_SECTOR_ALIGNED(*disc_address))
if (*disc_address + *fg_length > dr->capacity || !IS_SECTOR_ALIGNED(*disc_address, dr->sector_size))
{
dprintf("Disc address range :%u/%016llX-%016llX, limit %016llX, %ssector aligned\n",
drive, *disc_address, *disc_address + *fg_length, dr->capacity, IS_SECTOR_ALIGNED(*disc_address) ? "is " : "not ");
drive, *disc_address, *disc_address + *fg_length, dr->capacity, IS_SECTOR_ALIGNED(*disc_address, dr->sector_size) ? "is " : "not ");
e.number = BadParmsErr;
goto exit;
}
......@@ -356,9 +356,9 @@ low_level_error_t discop(uint32_t reason,
* - must not exceed 256 sectors (LBA28 or CHS) or 65536 sectors (LBA48)
*/
{ /* remove warnings about jump past initialisation of variables */
uint64_t end_down = ROUND_DOWN_64(*disc_address + *fg_length, LOG2_SECTOR_SIZE);
uint64_t end_up = ROUND_UP_64(*disc_address + *fg_length, LOG2_SECTOR_SIZE);
uint32_t chunk_size = dr->lba48 ? 65536 << LOG2_SECTOR_SIZE : 256 << LOG2_SECTOR_SIZE;
uint64_t end_down = ROUND_DOWN_64(*disc_address + *fg_length, dr->log2_sector_size);
uint64_t end_up = ROUND_UP_64(*disc_address + *fg_length, dr->log2_sector_size);
uint32_t chunk_size = dr->lba48 ? 65536 << dr->log2_sector_size : 256 << dr->log2_sector_size;
dprintf("%016llX/%016llX/%016llX, chunk=%08X\n", *disc_address, end_down, end_up, chunk_size);
block_or_scatter_t ptr_for_verify_ops;
if (reason == DiscOp_Verify)
......
......@@ -81,7 +81,25 @@ void drive_attached(uint32_t cpid, uint32_t deviceid, bool packet_device)
}
if (i < NUM_FLOPPIES + NUM_WINNIES)
{
dr->block_buffer = malloc(SECTOR_SIZE);
/* Interpret sector size */
if ((dr->identify_info[OFFSET_PHY_LOG_SSZ] &
(PHY_LOG_SSZ_MBZ | PHY_LOG_SSZ_MBO | PHY_LOG_SSZ_SIZE_NOT_512)) ==
(PHY_LOG_SSZ_MBO | PHY_LOG_SSZ_SIZE_NOT_512))
{
uint32_t bit;
dr->sector_size = (dr->identify_info[OFFSET_SSZ_LO] |
(dr->identify_info[OFFSET_SSZ_HI] << 16)) << 1;
__asm {
CLZ bit, dr->sector_size
}
dr->log2_sector_size = 31 - bit;
}
else
{
dr->sector_size = 1u << 9;
dr->log2_sector_size = 9;
}
dr->block_buffer = malloc(dr->sector_size);
if (dr->block_buffer == NULL)
{
dprintf("fail to malloc block buffer\n");
......@@ -89,6 +107,8 @@ void drive_attached(uint32_t cpid, uint32_t deviceid, bool packet_device)
spinrw_write_unlock(&g_drive_lock);
return;
}
/* No more errors possible, so put this drive in the global drive list */
g_drive[i] = dr;
dr->drive = i - NUM_FLOPPIES + 4;
uint32_t standby_timer = 0;
......@@ -120,9 +140,9 @@ void drive_attached(uint32_t cpid, uint32_t deviceid, bool packet_device)
(COMMAND_SET_MBZ | COMMAND_SET_MBO | COMMAND_SET_LBA48)) ==
(COMMAND_SET_MBO | COMMAND_SET_LBA48);
if (dr->lba48)
dr->capacity = SECTOR_SIZE * *(uint64_t *)&dr->identify_info[OFFSET_MAX_LBA48];
dr->capacity = dr->sector_size * *(uint64_t *)&dr->identify_info[OFFSET_MAX_LBA48];
else
dr->capacity = SECTOR_SIZE * (uint64_t) *(uint32_t *)&dr->identify_info[OFFSET_MAX_LBA];
dr->capacity = dr->sector_size * (uint64_t) *(uint32_t *)&dr->identify_info[OFFSET_MAX_LBA];
dprintf("assigned to drive %u\n", dr->drive);
}
else
......
......@@ -436,14 +436,16 @@ _kernel_oserror *module_discop_handler(_kernel_swi_regs *r, void *pw)
_kernel_oserror *e;
uint32_t reason;
uint32_t flags;
uint32_t drive = (r->r[2] >> LegacyDiscAddress_DriveNumber_Shift) & LegacyDiscAddress_DriveNumber_Mask;
uint64_t disc_address;
uint8_t log2_sector_size;
IGNORE(pw);
dprintf("DiscOp %u, flags %03X, disc address %u/%08X, buffer %08X, length %u\n",
r->r[1] & DiscOp_Op_Mask,
r->r[1] &~ DiscOp_Op_Mask,
(uint32_t) r->r[2] >> 29,
r->r[2] &~ 0xE0000000,
drive,
r->r[2] & LegacyDiscAddress_SectorOffset_Mask,
r->r[3],
r->r[4]);
......@@ -457,18 +459,22 @@ _kernel_oserror *module_discop_handler(_kernel_swi_regs *r, void *pw)
/* else drop through */
case DiscOp_ReadSecs:
case DiscOp_WriteSecs:
flags = r->r[1] & (DiscOp_Op_ScatterList_Flag | DiscOp_Op_IgnoreEscape_Flag | DiscOp_Op_IgnoreTimeout_Flag | DiscOp_Op_BackgroundOp_Flag);
spinrw_read_lock(&g_drive_lock);
log2_sector_size = g_drive[drive - 4 + NUM_FLOPPIES]->log2_sector_size;
spinrw_read_unlock(&g_drive_lock);
flags = r->r[1] & (DiscOp_Op_ScatterList_Flag | DiscOp_Op_IgnoreEscape_Flag |
DiscOp_Op_IgnoreTimeout_Flag | DiscOp_Op_BackgroundOp_Flag);
flags *= ATAOp_Scatter / DiscOp_Op_ScatterList_Flag;
disc_address = ((uint64_t) r->r[2] & LegacyDiscAddress_SectorOffset_Mask) << LOG2_SECTOR_SIZE;
if (disc_address + r->r[4] >= 1ull << (LegacyDiscAddress_DriveNumber_Shift + LOG2_SECTOR_SIZE))
disc_address = ((uint64_t) r->r[2] & LegacyDiscAddress_SectorOffset_Mask) << log2_sector_size;
if (disc_address + r->r[4] >= 1ull << (LegacyDiscAddress_DriveNumber_Shift + log2_sector_size))
/* We won't be able to update the disc address properly on exit, at
* least in the SectorDiscOp world */
return (_kernel_oserror *) BadParmsErr;
e = discop(reason, flags,
(uint32_t) r->r[2] >> LegacyDiscAddress_DriveNumber_Shift, &disc_address,
drive, &disc_address,
(block_or_scatter_t *) &r->r[3], (size_t *) &r->r[4]
).oserror;
r->r[2] = (r->r[2] &~ LegacyDiscAddress_SectorOffset_Mask) | (uint32_t) (disc_address >> LOG2_SECTOR_SIZE);
r->r[2] = (r->r[2] &~ LegacyDiscAddress_SectorOffset_Mask) | (uint32_t) (disc_address >> log2_sector_size);
return e;
/* Ops that we don't support, but lack of support is harmless */
......
......@@ -96,14 +96,8 @@
/** Number of retries to use on verifies */
#define VERIFY_RETRIES (1) /* same as old ADFS uses for hard discs */
/** Bit shift to convert between bytes and sectors */
#define LOG2_SECTOR_SIZE (9)
/** Sector size in bytes */
#define SECTOR_SIZE ((1u<<LOG2_SECTOR_SIZE))
/** Test for sector alignment */
#define IS_SECTOR_ALIGNED(x) (((x) & (SECTOR_SIZE - 1)) == 0)
#define IS_SECTOR_ALIGNED(x,s) (((x) & ((s) - 1)) == 0)
/** A quick macro to silence compiler warnings about unused parameters */
#define IGNORE(x) do { (void)(x); } while(0)
......@@ -146,11 +140,21 @@ enum
#define OFFSET_MAX_LBA (60)
#define OFFSET_COMMAND_SET (83)
#define OFFSET_MAX_LBA48 (100)
#define OFFSET_PHY_LOG_SSZ (106)
#define OFFSET_SSZ_LO (117)
#define OFFSET_SSZ_HI (118)
#define COMMAND_SET_MBZ (1u<<15)
#define COMMAND_SET_MBO (1u<<14)
#define COMMAND_SET_LBA48 (1u<<10)
#define PHY_LOG_SSZ_MBZ (1u<<15)
#define PHY_LOG_SSZ_MBO (1u<<14)
#define PHY_LOG_SSZ_GT1_LOG_PER_PHY (1u<<13)
#define PHY_LOG_SSZ_SIZE_NOT_512 (1u<<12) /* In which case see 117-118 */
#define PHY_LOG_SSZ_COUNT_SHIFT 0
#define PHY_LOG_SSZ_COUNT_MASK (0xF<<PHY_LOG_SSZ_COUNT_SHIFT)
/* Types */
/** Parameter blocks for device control commands */
......@@ -286,8 +290,10 @@ typedef struct drive
uint8_t cpid; /**< ATADriver controller/port ID */
uint8_t deviceid; /**< ATADriver device ID */
uint8_t standby_timer; /**< Automatic standby timer period - meaning defined by ATA IDLE command (0 = off, 1-240 = timeout / 5 seconds, etc) */
uint8_t log2_sector_size; /**< Logical sector size, as a shift */
new_disc_error_t disc_error; /**< Most recent disc error */
uint8_t *block_buffer; /**< Sector-size buffer to handle misaligned reads/writes, allocated from RMA */
size_t sector_size; /**< Logical sector size, in bytes */
uint64_t capacity; /**< Disc size, in sectors */
uint16_t identify_info[256]; /**< Result of ATA IDENTIFY DEVICE or IDENTIFY PACKET DEVICE */
} drive_t;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment