From 1de50a2a94af10bf02124cac66da58783d602782 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Tue, 19 Nov 2024 00:25:42 +0200 Subject: [PATCH] Kernel: Improve ATA device initialization This does better detection of empty ports and fixes floating bus read-value from 0x00 to 0xFF. --- kernel/include/kernel/Storage/ATA/ATABus.h | 7 +- kernel/kernel/Storage/ATA/ATABus.cpp | 77 ++++++++++------------ 2 files changed, 36 insertions(+), 48 deletions(-) diff --git a/kernel/include/kernel/Storage/ATA/ATABus.h b/kernel/include/kernel/Storage/ATA/ATABus.h index 04b64a71..98aaa2b9 100644 --- a/kernel/include/kernel/Storage/ATA/ATABus.h +++ b/kernel/include/kernel/Storage/ATA/ATABus.h @@ -35,11 +35,10 @@ namespace Kernel {} BAN::ErrorOr initialize(); - void select_device(bool secondary); - BAN::ErrorOr identify(bool secondary, BAN::Span buffer); + void select_device(bool is_secondary); + BAN::ErrorOr identify(bool is_secondary, BAN::Span buffer); - void block_until_irq(); - //uint8_t device_index(const ATADevice&) const; + BAN::ErrorOr block_until_irq(); uint8_t io_read(uint16_t); void io_write(uint16_t, uint8_t); diff --git a/kernel/kernel/Storage/ATA/ATABus.cpp b/kernel/kernel/Storage/ATA/ATABus.cpp index 643a4685..346dc288 100644 --- a/kernel/kernel/Storage/ATA/ATABus.cpp +++ b/kernel/kernel/Storage/ATA/ATABus.cpp @@ -19,7 +19,7 @@ namespace Kernel if (bus_ptr == nullptr) return BAN::Error::from_errno(ENOMEM); auto bus = BAN::RefPtr::adopt(bus_ptr); - if (bus->io_read(ATA_PORT_STATUS) == 0x00) + if (bus->io_read(ATA_PORT_STATUS) == 0xFF) { dprintln("Floating ATA bus on IO port 0x{H}", base); return BAN::Error::from_errno(ENODEV); @@ -69,94 +69,83 @@ namespace Kernel SystemTimer::get().sleep_ns(400); } - void ATABus::select_device(bool secondary) + void ATABus::select_device(bool is_secondary) { - io_write(ATA_PORT_DRIVE_SELECT, 0xA0 | ((uint8_t)secondary << 4)); + io_write(ATA_PORT_DRIVE_SELECT, 0xA0 | ((uint8_t)is_secondary << 4)); select_delay(); } - BAN::ErrorOr ATABus::identify(bool secondary, BAN::Span buffer) + BAN::ErrorOr ATABus::identify(bool is_secondary, BAN::Span buffer) { - // Try to detect whether port contains device - uint8_t status = io_read(ATA_PORT_STATUS); - if (status & ATA_STATUS_BSY) - { - uint64_t timeout = SystemTimer::get().ms_since_boot() + s_ata_timeout_ms; - while ((status = io_read(ATA_PORT_STATUS)) & ATA_STATUS_BSY) - { - if (SystemTimer::get().ms_since_boot() >= timeout) - { - dprintln("BSY flag clear timeout, assuming no drive on port"); - return BAN::Error::from_errno(ETIMEDOUT); - } - } - } - if (__builtin_popcount(status) >= 4) - { - dprintln("STATUS contains garbage, assuming no drive on port"); - return BAN::Error::from_errno(EINVAL); - } - - select_device(secondary); + select_device(is_secondary); // Disable interrupts io_write(ATA_PORT_CONTROL, ATA_CONTROL_nIEN); + io_write(ATA_PORT_SECTOR_COUNT, 0); + io_write(ATA_PORT_LBA0, 0); + io_write(ATA_PORT_LBA1, 0); + io_write(ATA_PORT_LBA2, 0); io_write(ATA_PORT_COMMAND, ATA_COMMAND_IDENTIFY); SystemTimer::get().sleep_ms(1); // No device on port if (io_read(ATA_PORT_STATUS) == 0) - return BAN::Error::from_errno(EINVAL); + return BAN::Error::from_errno(ENODEV); - DeviceType type = DeviceType::ATA; + TRY(wait(false)); - if (wait(true).is_error()) + const uint8_t lba1 = io_read(ATA_PORT_LBA1); + const uint8_t lba2 = io_read(ATA_PORT_LBA2); + + auto device_type = DeviceType::ATA; + if (lba1 || lba2) { - uint8_t lba1 = io_read(ATA_PORT_LBA1); - uint8_t lba2 = io_read(ATA_PORT_LBA2); - if (lba1 == 0x14 && lba2 == 0xEB) - type = DeviceType::ATAPI; + device_type = DeviceType::ATAPI; else if (lba1 == 0x69 && lba2 == 0x96) - type = DeviceType::ATAPI; + device_type = DeviceType::ATAPI; else { - dprintln("Unsupported device type"); + dprintln("Unsupported device type {2H} {2H}", lba1, lba2); return BAN::Error::from_errno(EINVAL); } io_write(ATA_PORT_COMMAND, ATA_COMMAND_IDENTIFY_PACKET); SystemTimer::get().sleep_ms(1); - - if (auto res = wait(true); res.is_error()) - { - dprintln("Fatal error: {}", res.error()); - return BAN::Error::from_errno(EINVAL); - } } + TRY(wait(true)); + ASSERT(buffer.size() >= 256); read_buffer(ATA_PORT_DATA, buffer.data(), 256); - return type; + return device_type; } void ATABus::handle_irq() { - ASSERT(!m_has_got_irq); if (io_read(ATA_PORT_STATUS) & ATA_STATUS_ERR) dprintln("ATA Error: {}", error()); - m_has_got_irq.store(true); + + bool expected { false }; + [[maybe_unused]] bool success = m_has_got_irq.compare_exchange(expected, true); + ASSERT(success); } - void ATABus::block_until_irq() + BAN::ErrorOr ATABus::block_until_irq() { + const uint64_t timeout_ms = SystemTimer::get().ms_since_boot() + s_ata_timeout_ms; + bool expected { true }; while (!m_has_got_irq.compare_exchange(expected, false)) { + if (SystemTimer::get().ms_since_boot() >= timeout_ms) + return BAN::Error::from_errno(ETIMEDOUT); Processor::pause(); expected = true; } + + return {}; } uint8_t ATABus::io_read(uint16_t port)