disk: Support a non-fixed (logical) SECTOR_SIZE

This allows a single build to support ATA drives with (eg) 512B and 4K
 logical sector sizes.  This is needed because ATA drives are user-
 replaceable and we don't know what could get plugged in.

 * Add disk_get_log_sector_size() API  (no-op for non-ATA storage)
 * Mostly a no-op if MAX_LOG_SECTOR_SIZE is not enabled
 * Sanity-check that storage's logical sector size is not larger
   than what we're built for

NOTE:  Other layers (eg ATA, FAT, etc) still need to be made aware of this.

Change-Id: Id6183ef0573cb0778fa9a91302e600c3e710eebd
This commit is contained in:
Solomon Peachy 2024-11-02 09:41:26 -04:00
parent 209aeff5b1
commit a8c52b1bfb
2 changed files with 68 additions and 11 deletions

View file

@ -29,6 +29,7 @@
#include "dir.h"
#include "rb_namespace.h"
#include "disk.h"
#include "panic.h"
#if defined(HAVE_BOOTDATA) && !defined(SIMULATOR) && !defined(BOOTLOADER)
#include "bootdata.h"
@ -110,7 +111,11 @@ static void init_volume(struct volumeinfo *vi, int drive, int part)
}
#ifdef MAX_LOG_SECTOR_SIZE
static int disk_sector_multiplier[NUM_DRIVES] =
#if !(CONFIG_STORAGE & STORAGE_ATA)
#error "MAX_LOG_SECTOR_SIZE only supported for STORAGE_ATA"
#endif
static uint16_t disk_sector_multiplier[NUM_DRIVES] =
{ [0 ... NUM_DRIVES-1] = 1 };
int disk_get_sector_multiplier(IF_MD_NONVOID(int drive))
@ -125,6 +130,33 @@ int disk_get_sector_multiplier(IF_MD_NONVOID(int drive))
}
#endif /* MAX_LOG_SECTOR_SIZE */
#if (CONFIG_STORAGE & STORAGE_ATA) // XXX make this more generic?
static uint16_t disk_log_sector_size[NUM_DRIVES] =
{ [0 ... NUM_DRIVES-1] = SECTOR_SIZE }; /* Updated from STORAGE_INFO */
int disk_get_log_sector_size(IF_MD_NONVOID(int drive))
{
if (!CHECK_DRV(drive))
return 0;
disk_reader_lock();
int size = disk_log_sector_size[IF_MD_DRV(drive)];
disk_reader_unlock();
return size;
}
#ifdef HAVE_MULTIDRIVE
#define LOG_SECTOR_SIZE(__drive) disk_log_sector_size[__drive]
#else
#define LOG_SECTOR_SIZE(__drive) disk_log_sector_size[0]
#endif /* HAVE_MULTIDRIVE */
#else /* !STORAGE_ATA */
#define LOG_SECTOR_SIZE(__drive) SECTOR_SIZE
int disk_get_log_sector_size(IF_MD_NONVOID(int drive))
{
IF_MD((void)drive);
return SECTOR_SIZE;
}
#endif /* !CONFIG_STORAGE & STORAGE_ATA */
bool disk_init(IF_MD_NONVOID(int drive))
{
if (!CHECK_DRV(drive))
@ -134,7 +166,30 @@ bool disk_init(IF_MD_NONVOID(int drive))
if (!sector)
return false;
memset(sector, 0, SECTOR_SIZE);
#if (CONFIG_STORAGE & STORAGE_ATA)
/* Query logical sector size */
struct storage_info *info = (struct storage_info*) sector;
storage_get_info(IF_MD_DRV(drive), info);
disk_writer_lock();
#ifdef MAX_LOG_SECTOR_SIZE
disk_log_sector_size[IF_MD_DRV(drive)] = info->sector_size;
#endif
disk_writer_unlock();
#ifdef MAX_LOG_SECTOR_SIZE
if (info->sector_size > MAX_LOG_SECTOR_SIZE) {
panicf("Unsupported logical sector size: %d",
info->sector_size);
}
#else
if (info->sector_size != SECTOR_SIZE) {
panicf("Unsupported logical sector size: %d",
info->sector_size);
}
#endif
#endif /* CONFIG_STORAGE & STORAGE_ATA */
memset(sector, 0, LOG_SECTOR_SIZE(drive));
storage_read_sectors(IF_MD(drive,) 0, 1, sector);
bool init = false;
@ -214,7 +269,7 @@ reload:
storage_read_sectors(IF_MD(drive,) part_lba, 1, sector);
uint8_t *pptr = ptr;
while (part < MAX_PARTITIONS_PER_DRIVE && part_entries) {
if (pptr - ptr >= SECTOR_SIZE) {
if (pptr - ptr >= LOG_SECTOR_SIZE(drive)) {
part_lba++;
goto reload;
}
@ -337,7 +392,7 @@ int disk_mount(int drive)
if (!fat_mount(IF_MV(volume,) IF_MD(drive,) 0))
{
#ifdef MAX_LOG_SECTOR_SIZE
disk_sector_multiplier[drive] = fat_get_bytes_per_sector(IF_MV(volume)) / SECTOR_SIZE;
disk_sector_multiplier[drive] = fat_get_bytes_per_sector(IF_MV(volume)) / LOG_SECTOR_SIZE(drive);
#endif
mounted = 1;
init_volume(&volumes[volume], drive, 0);
@ -356,7 +411,7 @@ int disk_mount(int drive)
DEBUGF("Trying to mount partition %d.\n", i);
#ifdef MAX_LOG_SECTOR_SIZE
for (int j = 1; j <= (MAX_LOG_SECTOR_SIZE/SECTOR_SIZE); j <<= 1)
for (int j = 1; j <= (MAX_LOG_SECTOR_SIZE/LOG_SECTOR_SIZE(drive)); j <<= 1)
{
if (!fat_mount(IF_MV(volume,) IF_MD(drive,) pinfo[i].start * j))
{

View file

@ -47,10 +47,12 @@ int disk_mount(int drive);
int disk_unmount_all(void);
int disk_unmount(int drive);
/* The number of 512-byte sectors in a "logical" sector. Needed for ipod 5.5G */
/* Used when the drive's logical sector size is smaller than the sector size used by the partition table and filesystem. Notably needed for ipod 5.5G/6G. */
#ifdef MAX_LOG_SECTOR_SIZE
int disk_get_sector_multiplier(IF_MD_NONVOID(int drive));
#endif
/* The size of the drive's smallest addressible unit */
int disk_get_log_sector_size(IF_MD_NONVOID(int drive));
bool disk_present(IF_MD_NONVOID(int drive));