Kernel: Add support for ATA CHS addressing and cleanup code
I thought that I had an PC without LBA support so I implement support for CHS. Turns out that my ATA device detection was broken and was no device on that port and initialize data was just garbage. Now that I added CHS, I guess I should just keep it in :) Both ATA read and write are now combined into a single function to avoid code duplication.
This commit is contained in:
parent
1de50a2a94
commit
c07fd265f0
|
@ -14,7 +14,6 @@ namespace Kernel
|
|||
Ext2_NoInodes,
|
||||
Storage_Boundaries,
|
||||
Storage_GPTHeader,
|
||||
ATA_NoLBA,
|
||||
ATA_AMNF,
|
||||
ATA_TKZNF,
|
||||
ATA_ABRT,
|
||||
|
|
|
@ -35,6 +35,8 @@ namespace Kernel
|
|||
{}
|
||||
BAN::ErrorOr<void> initialize();
|
||||
|
||||
BAN::ErrorOr<void> send_command(ATADevice&, uint64_t lba, uint64_t sector_count, bool write);
|
||||
|
||||
void select_device(bool is_secondary);
|
||||
BAN::ErrorOr<DeviceType> identify(bool is_secondary, BAN::Span<uint16_t> buffer);
|
||||
|
||||
|
|
|
@ -26,11 +26,12 @@ namespace Kernel
|
|||
|
||||
uint32_t words_per_sector() const { return m_sector_words; }
|
||||
uint64_t sector_count() const { return m_lba_count; }
|
||||
bool has_lba() const { return m_has_lba; }
|
||||
|
||||
BAN::StringView model() const { return m_model; }
|
||||
BAN::StringView name() const { return m_name; }
|
||||
BAN::StringView name() const override { return m_name; }
|
||||
|
||||
virtual dev_t rdev() const override { return m_rdev; }
|
||||
dev_t rdev() const override { return m_rdev; }
|
||||
|
||||
protected:
|
||||
ATABaseDevice();
|
||||
|
@ -42,6 +43,7 @@ namespace Kernel
|
|||
uint32_t m_command_set;
|
||||
uint32_t m_sector_words;
|
||||
uint64_t m_lba_count;
|
||||
bool m_has_lba;
|
||||
char m_model[41];
|
||||
char m_name[4] {};
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@ namespace Kernel
|
|||
"Ext2 filesystem out of inodes",
|
||||
"Attempted to access outside of device boundaries",
|
||||
"Device has invalid GPT header",
|
||||
"Device does not support LBA addressing",
|
||||
"Address mark not found",
|
||||
"Track zero not found",
|
||||
"Aborted command",
|
||||
|
|
|
@ -245,29 +245,12 @@ namespace Kernel
|
|||
|
||||
LockGuard _(m_mutex);
|
||||
|
||||
if (lba < (1 << 28))
|
||||
{
|
||||
// LBA28
|
||||
io_write(ATA_PORT_DRIVE_SELECT, 0xE0 | ((uint8_t)device.is_secondary() << 4) | ((lba >> 24) & 0x0F));
|
||||
select_delay();
|
||||
io_write(ATA_PORT_CONTROL, 0);
|
||||
TRY(send_command(device, lba, sector_count, false));
|
||||
|
||||
io_write(ATA_PORT_SECTOR_COUNT, sector_count);
|
||||
io_write(ATA_PORT_LBA0, (uint8_t)(lba >> 0));
|
||||
io_write(ATA_PORT_LBA1, (uint8_t)(lba >> 8));
|
||||
io_write(ATA_PORT_LBA2, (uint8_t)(lba >> 16));
|
||||
io_write(ATA_PORT_COMMAND, ATA_COMMAND_READ_SECTORS);
|
||||
|
||||
for (uint32_t sector = 0; sector < sector_count; sector++)
|
||||
{
|
||||
block_until_irq();
|
||||
read_buffer(ATA_PORT_DATA, (uint16_t*)buffer.data() + sector * device.words_per_sector(), device.words_per_sector());
|
||||
}
|
||||
}
|
||||
else
|
||||
for (uint32_t sector = 0; sector < sector_count; sector++)
|
||||
{
|
||||
// LBA48
|
||||
ASSERT(false);
|
||||
TRY(block_until_irq());
|
||||
read_buffer(ATA_PORT_DATA, (uint16_t*)buffer.data() + sector * device.words_per_sector(), device.words_per_sector());
|
||||
}
|
||||
|
||||
return {};
|
||||
|
@ -282,33 +265,60 @@ namespace Kernel
|
|||
|
||||
LockGuard _(m_mutex);
|
||||
|
||||
if (lba < (1 << 28))
|
||||
{
|
||||
// LBA28
|
||||
io_write(ATA_PORT_DRIVE_SELECT, 0xE0 | ((uint8_t)device.is_secondary() << 4) | ((lba >> 24) & 0x0F));
|
||||
select_delay();
|
||||
io_write(ATA_PORT_CONTROL, 0);
|
||||
TRY(send_command(device, lba, sector_count, true));
|
||||
|
||||
io_write(ATA_PORT_SECTOR_COUNT, sector_count);
|
||||
io_write(ATA_PORT_LBA0, (uint8_t)(lba >> 0));
|
||||
io_write(ATA_PORT_LBA1, (uint8_t)(lba >> 8));
|
||||
io_write(ATA_PORT_LBA2, (uint8_t)(lba >> 16));
|
||||
io_write(ATA_PORT_COMMAND, ATA_COMMAND_WRITE_SECTORS);
|
||||
|
||||
for (uint32_t sector = 0; sector < sector_count; sector++)
|
||||
{
|
||||
write_buffer(ATA_PORT_DATA, (uint16_t*)buffer.data() + sector * device.words_per_sector(), device.words_per_sector());
|
||||
block_until_irq();
|
||||
}
|
||||
}
|
||||
else
|
||||
for (uint32_t sector = 0; sector < sector_count; sector++)
|
||||
{
|
||||
// LBA48
|
||||
ASSERT(false);
|
||||
write_buffer(ATA_PORT_DATA, (uint16_t*)buffer.data() + sector * device.words_per_sector(), device.words_per_sector());
|
||||
TRY(block_until_irq());
|
||||
}
|
||||
|
||||
io_write(ATA_PORT_COMMAND, ATA_COMMAND_CACHE_FLUSH);
|
||||
block_until_irq();
|
||||
TRY(block_until_irq());
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> ATABus::send_command(ATADevice& device, uint64_t lba, uint64_t sector_count, bool write)
|
||||
{
|
||||
uint8_t io_select = 0;
|
||||
uint8_t io_lba0 = 0;
|
||||
uint8_t io_lba1 = 0;
|
||||
uint8_t io_lba2 = 0;
|
||||
|
||||
if (lba >= (1 << 28))
|
||||
{
|
||||
dwarnln("LBA48 addressing not supported");
|
||||
return BAN::Error::from_errno(ENOTSUP);
|
||||
}
|
||||
else if (device.has_lba())
|
||||
{
|
||||
io_select = 0xE0 | ((uint8_t)device.is_secondary() << 4) | ((lba >> 24) & 0x0F);
|
||||
io_lba0 = (lba >> 0) & 0xFF;
|
||||
io_lba1 = (lba >> 8) & 0xFF;
|
||||
io_lba2 = (lba >> 16) & 0xFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
const uint8_t sector = (lba % 63) + 1;
|
||||
const uint8_t head = (lba + 1 - sector) % (16 * 63) / 63;
|
||||
const uint16_t cylinder = (lba + 1 - sector) / (16 * 63);
|
||||
|
||||
io_select = 0xA0 | ((uint8_t)device.is_secondary() << 4) | head;
|
||||
io_lba0 = sector;
|
||||
io_lba1 = (cylinder >> 0) & 0xFF;
|
||||
io_lba2 = (cylinder >> 8) & 0xFF;
|
||||
}
|
||||
|
||||
io_write(ATA_PORT_DRIVE_SELECT, io_select);
|
||||
select_delay();
|
||||
io_write(ATA_PORT_CONTROL, 0);
|
||||
|
||||
io_write(ATA_PORT_SECTOR_COUNT, sector_count);
|
||||
io_write(ATA_PORT_LBA0, io_lba0);
|
||||
io_write(ATA_PORT_LBA1, io_lba1);
|
||||
io_write(ATA_PORT_LBA2, io_lba2);
|
||||
io_write(ATA_PORT_COMMAND, write ? ATA_COMMAND_WRITE_SECTORS : ATA_COMMAND_READ_SECTORS);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
|
|
@ -27,21 +27,20 @@ namespace Kernel
|
|||
{
|
||||
ASSERT(identify_data.size() >= 256);
|
||||
|
||||
m_signature = identify_data[ATA_IDENTIFY_SIGNATURE];
|
||||
m_signature = identify_data[ATA_IDENTIFY_SIGNATURE];
|
||||
m_capabilities = identify_data[ATA_IDENTIFY_CAPABILITIES];
|
||||
|
||||
m_command_set = 0;
|
||||
m_command_set |= (uint32_t)(identify_data[ATA_IDENTIFY_COMMAND_SET + 0] << 0);
|
||||
m_command_set |= (uint32_t)(identify_data[ATA_IDENTIFY_COMMAND_SET + 1] << 16);
|
||||
m_command_set = static_cast<uint32_t>(identify_data[ATA_IDENTIFY_COMMAND_SET + 0]) << 0;
|
||||
m_command_set |= static_cast<uint32_t>(identify_data[ATA_IDENTIFY_COMMAND_SET + 1]) << 16;
|
||||
|
||||
if (!(m_capabilities & ATA_CAPABILITIES_LBA))
|
||||
return BAN::Error::from_error_code(ErrorCode::ATA_NoLBA);
|
||||
m_has_lba = !!(m_capabilities & ATA_CAPABILITIES_LBA);
|
||||
|
||||
if ((identify_data[ATA_IDENTIFY_SECTOR_INFO] & (1 << 15)) == 0 &&
|
||||
(identify_data[ATA_IDENTIFY_SECTOR_INFO] & (1 << 14)) != 0 &&
|
||||
(identify_data[ATA_IDENTIFY_SECTOR_INFO] & (1 << 12)) != 0)
|
||||
{
|
||||
m_sector_words = *(uint32_t*)(identify_data.data() + ATA_IDENTIFY_SECTOR_WORDS);
|
||||
m_sector_words = static_cast<uint32_t>(identify_data[ATA_IDENTIFY_SECTOR_WORDS + 0]) << 0;
|
||||
m_sector_words |= static_cast<uint32_t>(identify_data[ATA_IDENTIFY_SECTOR_WORDS + 1]) << 16;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -50,9 +49,17 @@ namespace Kernel
|
|||
|
||||
m_lba_count = 0;
|
||||
if (m_command_set & ATA_COMMANDSET_LBA48_SUPPORTED)
|
||||
m_lba_count = *(uint64_t*)(identify_data.data() + ATA_IDENTIFY_LBA_COUNT_EXT);
|
||||
{
|
||||
m_lba_count = static_cast<uint64_t>(identify_data[ATA_IDENTIFY_LBA_COUNT_EXT + 0]) << 0;
|
||||
m_lba_count |= static_cast<uint64_t>(identify_data[ATA_IDENTIFY_LBA_COUNT_EXT + 1]) << 16;
|
||||
m_lba_count |= static_cast<uint64_t>(identify_data[ATA_IDENTIFY_LBA_COUNT_EXT + 2]) << 32;
|
||||
m_lba_count |= static_cast<uint64_t>(identify_data[ATA_IDENTIFY_LBA_COUNT_EXT + 3]) << 48;
|
||||
}
|
||||
if (m_lba_count < (1 << 28))
|
||||
m_lba_count = *(uint32_t*)(identify_data.data() + ATA_IDENTIFY_LBA_COUNT);
|
||||
{
|
||||
m_lba_count = static_cast<uint32_t>(identify_data[ATA_IDENTIFY_LBA_COUNT + 0]) << 0;
|
||||
m_lba_count |= static_cast<uint32_t>(identify_data[ATA_IDENTIFY_LBA_COUNT + 1]) << 16;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue