From dcc174b62e9da0777d49df8e043c25de9664db02 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Sun, 2 Apr 2023 18:26:19 +0300 Subject: [PATCH] Kernel: Move ATADevice to its own file from ATAController The API is kinda weird since device reads/writes go from ATADevice -> ATAController -> ATADevice but this is for now atleast necessary since ATAController has(?) to keep all devices from using the disks at the same time --- kernel/CMakeLists.txt | 1 + kernel/include/kernel/Storage/ATAController.h | 74 +---- .../include/kernel/Storage/ATADefinitions.h | 50 ++++ kernel/include/kernel/Storage/ATADevice.h | 82 ++++++ kernel/kernel/Storage/ATAController.cpp | 254 +----------------- kernel/kernel/Storage/ATADevice.cpp | 218 +++++++++++++++ 6 files changed, 354 insertions(+), 325 deletions(-) create mode 100644 kernel/include/kernel/Storage/ATADefinitions.h create mode 100644 kernel/include/kernel/Storage/ATADevice.h create mode 100644 kernel/kernel/Storage/ATADevice.cpp diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index c09448a5f1..e0fa099830 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -39,6 +39,7 @@ set(KERNEL_SOURCES kernel/SpinLock.cpp kernel/SSP.cpp kernel/Storage/ATAController.cpp + kernel/Storage/ATADevice.cpp kernel/Storage/StorageDevice.cpp kernel/Syscall.cpp kernel/Thread.cpp diff --git a/kernel/include/kernel/Storage/ATAController.h b/kernel/include/kernel/Storage/ATAController.h index a83211c87a..c747b3a01d 100644 --- a/kernel/include/kernel/Storage/ATAController.h +++ b/kernel/include/kernel/Storage/ATAController.h @@ -8,79 +8,7 @@ namespace Kernel { - class ATAController; - - class ATADevice final : public StorageDevice - { - public: - static BAN::ErrorOr create(ATAController*, uint16_t, uint16_t, uint8_t); - - virtual BAN::ErrorOr read_sectors(uint64_t, uint8_t, uint8_t*) override; - virtual BAN::ErrorOr write_sectors(uint64_t, uint8_t, const uint8_t*) override; - virtual uint32_t sector_size() const override { return m_sector_words * 2; } - virtual uint64_t total_size() const override { return m_lba_count * sector_size(); } - - BAN::StringView model() const { return m_model; } - - private: - ATADevice(ATAController* controller, uint16_t base, uint16_t ctrl, uint8_t index) - : m_controller(controller) - , m_base(base) - , m_ctrl(ctrl) - , m_index(index) - , m_slave_bit((index & 0x01) << 4) - { } - BAN::ErrorOr initialize(); - - uint8_t io_read(uint16_t); - void io_write(uint16_t, uint8_t); - void read_buffer(uint16_t, uint16_t*, size_t); - void write_buffer(uint16_t, const uint16_t*, size_t); - BAN::ErrorOr wait(bool); - BAN::Error error(); - - private: - enum class DeviceType - { - ATA, - ATAPI, - }; - - ATAController* m_controller; - const uint16_t m_base; - const uint16_t m_ctrl; - const uint8_t m_index; - const uint8_t m_slave_bit; - - DeviceType m_type; - uint16_t m_signature; - uint16_t m_capabilities; - uint32_t m_command_set; - uint32_t m_sector_words; - uint64_t m_lba_count; - char m_model[41]; - - friend class ATAController; - - public: - virtual ino_t ino() const override { return m_index; } - virtual Mode mode() const override { return { Mode::IFBLK }; } - virtual nlink_t nlink() const override { return 1; } - virtual uid_t uid() const override { return 0; } - virtual gid_t gid() const override { return 0; } - virtual off_t size() const override { return 0; } - virtual blksize_t blksize() const override { return sector_size(); } - virtual blkcnt_t blocks() const override { return 0; } - virtual dev_t dev() const override; - virtual dev_t rdev() const override { return 0x5429; } - - virtual BAN::StringView name() const override { return BAN::StringView(m_device_name, sizeof(m_device_name) - 1); } - - virtual BAN::ErrorOr read(size_t, void*, size_t) override; - - public: - char m_device_name[4] {}; - }; + class ATADevice; class ATAController final : public StorageController { diff --git a/kernel/include/kernel/Storage/ATADefinitions.h b/kernel/include/kernel/Storage/ATADefinitions.h new file mode 100644 index 0000000000..7559062bca --- /dev/null +++ b/kernel/include/kernel/Storage/ATADefinitions.h @@ -0,0 +1,50 @@ +#pragma once + +#define ATA_PORT_DATA 0x00 +#define ATA_PORT_ERROR 0x00 +#define ATA_PORT_SECTOR_COUNT 0x02 +#define ATA_PORT_LBA0 0x03 +#define ATA_PORT_LBA1 0x04 +#define ATA_PORT_LBA2 0x05 +#define ATA_PORT_DRIVE_SELECT 0x06 +#define ATA_PORT_COMMAND 0x07 +#define ATA_PORT_STATUS 0x07 + +#define ATA_PORT_CONTROL 0x10 +#define ATA_PORT_ALT_STATUS 0x10 + +#define ATA_CONTROL_nIEN 0x02 + +#define ATA_ERROR_AMNF 0x01 +#define ATA_ERROR_TKZNF 0x02 +#define ATA_ERROR_ABRT 0x04 +#define ATA_ERROR_MCR 0x08 +#define ATA_ERROR_IDNF 0x10 +#define ATA_ERROR_MC 0x20 +#define ATA_ERROR_UNC 0x40 +#define ATA_ERROR_BBK 0x80 + +#define ATA_STATUS_ERR 0x01 +#define ATA_STATUS_DF 0x02 +#define ATA_STATUS_DRQ 0x08 +#define ATA_STATUS_BSY 0x80 + +#define ATA_COMMAND_READ_SECTORS 0x20 +#define ATA_COMMAND_WRITE_SECTORS 0x30 +#define ATA_COMMAND_IDENTIFY_PACKET 0xA1 +#define ATA_COMMAND_CACHE_FLUSH 0xE7 +#define ATA_COMMAND_IDENTIFY 0xEC + +#define ATA_IDENTIFY_SIGNATURE 0 +#define ATA_IDENTIFY_MODEL 27 +#define ATA_IDENTIFY_CAPABILITIES 49 +#define ATA_IDENTIFY_LBA_COUNT 60 +#define ATA_IDENTIFY_COMMAND_SET 82 +#define ATA_IDENTIFY_LBA_COUNT_EXT 100 +#define ATA_IDENTIFY_SECTOR_INFO 106 +#define ATA_IDENTIFY_SECTOR_WORDS 117 + +#define ATA_COMMANDSET_LBA48_SUPPORTED (1 << 26) + +#define ATA_CAPABILITIES_LBA (1 << 9) +#define ATA_CAPABILITIES_DMA (1 << 8) \ No newline at end of file diff --git a/kernel/include/kernel/Storage/ATADevice.h b/kernel/include/kernel/Storage/ATADevice.h new file mode 100644 index 0000000000..e90913d48d --- /dev/null +++ b/kernel/include/kernel/Storage/ATADevice.h @@ -0,0 +1,82 @@ +#pragma once + +#include + +namespace Kernel +{ + + class ATAController; + + class ATADevice final : public StorageDevice + { + public: + static BAN::ErrorOr create(ATAController*, uint16_t, uint16_t, uint8_t); + + virtual BAN::ErrorOr read_sectors(uint64_t, uint8_t, uint8_t*) override; + virtual BAN::ErrorOr write_sectors(uint64_t, uint8_t, const uint8_t*) override; + virtual uint32_t sector_size() const override { return m_sector_words * 2; } + virtual uint64_t total_size() const override { return m_lba_count * sector_size(); } + + BAN::StringView model() const { return m_model; } + + private: + ATADevice(ATAController* controller, uint16_t base, uint16_t ctrl, uint8_t index) + : m_controller(controller) + , m_base(base) + , m_ctrl(ctrl) + , m_index(index) + , m_slave_bit((index & 0x01) << 4) + { } + BAN::ErrorOr initialize(); + + uint8_t io_read(uint16_t); + void io_write(uint16_t, uint8_t); + void read_buffer(uint16_t, uint16_t*, size_t); + void write_buffer(uint16_t, const uint16_t*, size_t); + BAN::ErrorOr wait(bool); + BAN::Error error(); + + private: + enum class DeviceType + { + ATA, + ATAPI, + }; + + ATAController* m_controller; + const uint16_t m_base; + const uint16_t m_ctrl; + const uint8_t m_index; + const uint8_t m_slave_bit; + + DeviceType m_type; + uint16_t m_signature; + uint16_t m_capabilities; + uint32_t m_command_set; + uint32_t m_sector_words; + uint64_t m_lba_count; + char m_model[41]; + + friend class ATAController; + + public: + virtual ino_t ino() const override { return m_index; } + virtual Mode mode() const override { return { Mode::IFBLK }; } + virtual nlink_t nlink() const override { return 1; } + virtual uid_t uid() const override { return 0; } + virtual gid_t gid() const override { return 0; } + virtual off_t size() const override { return 0; } + virtual blksize_t blksize() const override { return sector_size(); } + virtual blkcnt_t blocks() const override { return 0; } + virtual dev_t dev() const override; + virtual dev_t rdev() const override { return 0x5429; } + + virtual BAN::StringView name() const override { return BAN::StringView(m_device_name, sizeof(m_device_name) - 1); } + + virtual BAN::ErrorOr read(size_t, void*, size_t) override; + + public: + char m_device_name[4] {}; + }; + +} \ No newline at end of file diff --git a/kernel/kernel/Storage/ATAController.cpp b/kernel/kernel/Storage/ATAController.cpp index b358045f61..2a6bfd3d30 100644 --- a/kernel/kernel/Storage/ATAController.cpp +++ b/kernel/kernel/Storage/ATAController.cpp @@ -1,68 +1,12 @@ #include -#include #include #include - -#define ATA_PORT_DATA 0x00 -#define ATA_PORT_ERROR 0x00 -#define ATA_PORT_SECTOR_COUNT 0x02 -#define ATA_PORT_LBA0 0x03 -#define ATA_PORT_LBA1 0x04 -#define ATA_PORT_LBA2 0x05 -#define ATA_PORT_DRIVE_SELECT 0x06 -#define ATA_PORT_COMMAND 0x07 -#define ATA_PORT_STATUS 0x07 - -#define ATA_PORT_CONTROL 0x10 -#define ATA_PORT_ALT_STATUS 0x10 - -#define ATA_CONTROL_nIEN 0x02 - -#define ATA_ERROR_AMNF 0x01 -#define ATA_ERROR_TKZNF 0x02 -#define ATA_ERROR_ABRT 0x04 -#define ATA_ERROR_MCR 0x08 -#define ATA_ERROR_IDNF 0x10 -#define ATA_ERROR_MC 0x20 -#define ATA_ERROR_UNC 0x40 -#define ATA_ERROR_BBK 0x80 - -#define ATA_STATUS_ERR 0x01 -#define ATA_STATUS_DF 0x02 -#define ATA_STATUS_DRQ 0x08 -#define ATA_STATUS_BSY 0x80 - -#define ATA_COMMAND_READ_SECTORS 0x20 -#define ATA_COMMAND_WRITE_SECTORS 0x30 -#define ATA_COMMAND_IDENTIFY_PACKET 0xA1 -#define ATA_COMMAND_CACHE_FLUSH 0xE7 -#define ATA_COMMAND_IDENTIFY 0xEC - -#define ATA_IDENTIFY_SIGNATURE 0 -#define ATA_IDENTIFY_MODEL 27 -#define ATA_IDENTIFY_CAPABILITIES 49 -#define ATA_IDENTIFY_LBA_COUNT 60 -#define ATA_IDENTIFY_COMMAND_SET 82 -#define ATA_IDENTIFY_LBA_COUNT_EXT 100 -#define ATA_IDENTIFY_SECTOR_INFO 106 -#define ATA_IDENTIFY_SECTOR_WORDS 117 - -#define ATA_COMMANDSET_LBA48_SUPPORTED (1 << 26) +#include +#include namespace Kernel { - BAN::ErrorOr ATADevice::create(ATAController* controller, uint16_t base, uint16_t ctrl, uint8_t index) - { - ATADevice* device = new ATADevice(controller, base, ctrl, index); - if (device == nullptr) - return BAN::Error::from_errno(ENOMEM); - BAN::ScopeGuard guard([device] { device->unref(); }); - TRY(device->initialize()); - guard.disable(); - return device; - } - BAN::ErrorOr ATAController::create(const PCIDevice& device) { ATAController* controller = new ATAController(); @@ -74,90 +18,6 @@ namespace Kernel return controller; } - BAN::ErrorOr ATADevice::initialize() - { - io_write(ATA_PORT_CONTROL, ATA_CONTROL_nIEN); - - io_write(ATA_PORT_DRIVE_SELECT, 0xA0 | m_slave_bit); - PIT::sleep(1); - - io_write(ATA_PORT_COMMAND, ATA_COMMAND_IDENTIFY); - PIT::sleep(1); - - if (io_read(ATA_PORT_STATUS) == 0) - return BAN::Error::from_c_string(""); - - uint8_t status = 0; - while (true) - { - status = io_read(ATA_PORT_STATUS); - if (status & ATA_STATUS_ERR) - break; - if (!(status & ATA_STATUS_BSY) && (status && ATA_STATUS_DRQ)) - break; - } - - if (status & ATA_STATUS_ERR) - { - uint8_t lba1 = io_read(ATA_PORT_LBA1); - uint8_t lba2 = io_read(ATA_PORT_LBA2); - - if (lba1 == 0x14 && lba2 == 0xEB) - m_type = ATADevice::DeviceType::ATAPI; - else if (lba1 == 0x69 && lba2 == 0x96) - m_type = ATADevice::DeviceType::ATAPI; - else - return BAN::Error::from_c_string("Not ATA/ATAPI device"); - - io_write(ATA_PORT_COMMAND, ATA_COMMAND_IDENTIFY_PACKET); - PIT::sleep(1); - } - else - { - m_type = ATADevice::DeviceType::ATA; - } - - uint16_t buffer[256] {}; - read_buffer(ATA_PORT_DATA, buffer, 256); - - m_signature = *(uint16_t*)(buffer + ATA_IDENTIFY_SIGNATURE); - m_capabilities = *(uint16_t*)(buffer + ATA_IDENTIFY_CAPABILITIES); - m_command_set = *(uint32_t*)(buffer + ATA_IDENTIFY_COMMAND_SET); - - if ((buffer[ATA_IDENTIFY_SECTOR_INFO] & (1 << 15)) == 0 && - (buffer[ATA_IDENTIFY_SECTOR_INFO] & (1 << 14)) != 0 && - (buffer[ATA_IDENTIFY_SECTOR_INFO] & (1 << 12)) != 0) - { - m_sector_words = *(uint32_t*)(buffer + ATA_IDENTIFY_SECTOR_WORDS); - } - else - { - m_sector_words = 256; - } - - m_lba_count = 0; - if (m_command_set & ATA_COMMANDSET_LBA48_SUPPORTED) - m_lba_count = *(uint64_t*)(buffer + ATA_IDENTIFY_LBA_COUNT_EXT); - if (m_lba_count < (1 << 28)) - m_lba_count = *(uint32_t*)(buffer + ATA_IDENTIFY_LBA_COUNT); - - for (int i = 0; i < 20; i++) - { - uint16_t word = buffer[ATA_IDENTIFY_MODEL + i]; - m_model[2 * i + 0] = word >> 8; - m_model[2 * i + 1] = word & 0xFF; - } - m_model[40] = 0; - - m_device_name[0] = 'h'; - m_device_name[1] = 'd'; - m_device_name[2] = 'a' + m_index; - m_device_name[3] = '\0'; - - TRY(initialize_partitions()); - return {}; - } - BAN::ErrorOr ATAController::initialize(const PCIDevice& pci_device) { struct Bus @@ -275,114 +135,4 @@ namespace Kernel return {}; } - BAN::ErrorOr ATADevice::read_sectors(uint64_t lba, uint8_t sector_count, uint8_t* buffer) - { - TRY(m_controller->read(this, lba, sector_count, buffer)); - return {}; - } - - BAN::ErrorOr ATADevice::write_sectors(uint64_t lba, uint8_t sector_count, const uint8_t* buffer) - { - TRY(m_controller->write(this, lba, sector_count, buffer)); - return {}; - } - - uint8_t ATADevice::io_read(uint16_t port) - { - if (port <= 0x07) - return IO::inb(m_base + port); - if (0x10 <= port && port <= 0x11) - return IO::inb(m_ctrl + port - 0x10); - ASSERT_NOT_REACHED(); - } - - void ATADevice::read_buffer(uint16_t port, uint16_t* buffer, size_t words) - { - if (port <= 0x07) - return IO::insw(m_base + port - 0x00, buffer, words); - if (0x10 <= port && port <= 0x11) - return IO::insw(m_ctrl + port - 0x10, buffer, words); - ASSERT_NOT_REACHED(); - } - - void ATADevice::io_write(uint16_t port, uint8_t data) - { - if (port <= 0x07) - return IO::outb(m_base + port, data); - if (0x10 <= port && port <= 0x11) - return IO::outb(m_ctrl + port - 0x10, data); - ASSERT_NOT_REACHED(); - } - - void ATADevice::write_buffer(uint16_t port, const uint16_t* buffer, size_t words) - { - uint16_t io_port = 0; - if (port <= 0x07) - io_port = m_base + port; - if (0x10 <= port && port <= 0x11) - io_port = m_ctrl + port - 0x10; - ASSERT(io_port); - for (size_t i = 0; i < words; i++) - IO::outw(io_port, buffer[i]); - } - - BAN::ErrorOr ATADevice::wait(bool wait_drq) - { - for (uint32_t i = 0; i < 4; i++) - io_read(ATA_PORT_ALT_STATUS); - - uint8_t status = ATA_STATUS_BSY; - while (status & ATA_STATUS_BSY) - status = io_read(ATA_PORT_STATUS); - - while (wait_drq && !(status & ATA_STATUS_DRQ)) - { - if (status & ATA_STATUS_ERR) - return error(); - if (status & ATA_STATUS_DF) - return BAN::Error::from_errno(EIO); - status = io_read(ATA_PORT_STATUS); - } - - return {}; - } - - BAN::Error ATADevice::error() - { - uint8_t err = io_read(ATA_PORT_ERROR); - if (err & ATA_ERROR_AMNF) - return BAN::Error::from_c_string("Address mark not found."); - if (err & ATA_ERROR_TKZNF) - return BAN::Error::from_c_string("Track zero not found."); - if (err & ATA_ERROR_ABRT) - return BAN::Error::from_c_string("Aborted command."); - if (err & ATA_ERROR_MCR) - return BAN::Error::from_c_string("Media change request."); - if (err & ATA_ERROR_IDNF) - return BAN::Error::from_c_string("ID not found."); - if (err & ATA_ERROR_MC) - return BAN::Error::from_c_string("Media changed."); - if (err & ATA_ERROR_UNC) - return BAN::Error::from_c_string("Uncorrectable data error."); - if (err & ATA_ERROR_BBK) - return BAN::Error::from_c_string("Bad Block detected."); - ASSERT_NOT_REACHED(); - } - - dev_t ATADevice::dev() const - { - ASSERT(m_controller); - return m_controller->dev(); - } - - BAN::ErrorOr ATADevice::read(size_t offset, void* buffer, size_t bytes) - { - if (offset % sector_size() || bytes % sector_size()) - return BAN::Error::from_errno(EINVAL); - if (offset == total_size()) - return 0; - TRY(read_sectors(offset / sector_size(), bytes / sector_size(), (uint8_t*)buffer)); - return bytes; - } - } \ No newline at end of file diff --git a/kernel/kernel/Storage/ATADevice.cpp b/kernel/kernel/Storage/ATADevice.cpp new file mode 100644 index 0000000000..6bc88977b0 --- /dev/null +++ b/kernel/kernel/Storage/ATADevice.cpp @@ -0,0 +1,218 @@ +#include +#include +#include +#include +#include + +namespace Kernel +{ + + BAN::ErrorOr ATADevice::create(ATAController* controller, uint16_t base, uint16_t ctrl, uint8_t index) + { + ATADevice* device = new ATADevice(controller, base, ctrl, index); + if (device == nullptr) + return BAN::Error::from_errno(ENOMEM); + BAN::ScopeGuard guard([device] { device->unref(); }); + TRY(device->initialize()); + guard.disable(); + return device; + } + + BAN::ErrorOr ATADevice::initialize() + { + io_write(ATA_PORT_CONTROL, ATA_CONTROL_nIEN); + + io_write(ATA_PORT_DRIVE_SELECT, 0xA0 | m_slave_bit); + PIT::sleep(1); + + io_write(ATA_PORT_COMMAND, ATA_COMMAND_IDENTIFY); + PIT::sleep(1); + + if (io_read(ATA_PORT_STATUS) == 0) + return BAN::Error::from_c_string(""); + + uint8_t status = 0; + while (true) + { + status = io_read(ATA_PORT_STATUS); + if (status & ATA_STATUS_ERR) + break; + if (!(status & ATA_STATUS_BSY) && (status && ATA_STATUS_DRQ)) + break; + } + + if (status & ATA_STATUS_ERR) + { + uint8_t lba1 = io_read(ATA_PORT_LBA1); + uint8_t lba2 = io_read(ATA_PORT_LBA2); + + if (lba1 == 0x14 && lba2 == 0xEB) + m_type = ATADevice::DeviceType::ATAPI; + else if (lba1 == 0x69 && lba2 == 0x96) + m_type = ATADevice::DeviceType::ATAPI; + else + return BAN::Error::from_c_string("Not ATA/ATAPI device"); + + io_write(ATA_PORT_COMMAND, ATA_COMMAND_IDENTIFY_PACKET); + PIT::sleep(1); + } + else + { + m_type = ATADevice::DeviceType::ATA; + } + + uint16_t buffer[256] {}; + read_buffer(ATA_PORT_DATA, buffer, 256); + + m_signature = *(uint16_t*)(buffer + ATA_IDENTIFY_SIGNATURE); + m_capabilities = *(uint16_t*)(buffer + ATA_IDENTIFY_CAPABILITIES); + m_command_set = *(uint32_t*)(buffer + ATA_IDENTIFY_COMMAND_SET); + + if (!(m_capabilities & ATA_CAPABILITIES_LBA)) + return BAN::Error::from_c_string("Device does not support LBA addressing"); + + if ((buffer[ATA_IDENTIFY_SECTOR_INFO] & (1 << 15)) == 0 && + (buffer[ATA_IDENTIFY_SECTOR_INFO] & (1 << 14)) != 0 && + (buffer[ATA_IDENTIFY_SECTOR_INFO] & (1 << 12)) != 0) + { + m_sector_words = *(uint32_t*)(buffer + ATA_IDENTIFY_SECTOR_WORDS); + } + else + { + m_sector_words = 256; + } + + m_lba_count = 0; + if (m_command_set & ATA_COMMANDSET_LBA48_SUPPORTED) + m_lba_count = *(uint64_t*)(buffer + ATA_IDENTIFY_LBA_COUNT_EXT); + if (m_lba_count < (1 << 28)) + m_lba_count = *(uint32_t*)(buffer + ATA_IDENTIFY_LBA_COUNT); + + for (int i = 0; i < 20; i++) + { + uint16_t word = buffer[ATA_IDENTIFY_MODEL + i]; + m_model[2 * i + 0] = word >> 8; + m_model[2 * i + 1] = word & 0xFF; + } + m_model[40] = 0; + + m_device_name[0] = 'h'; + m_device_name[1] = 'd'; + m_device_name[2] = 'a' + m_index; + m_device_name[3] = '\0'; + + TRY(initialize_partitions()); + return {}; + } + + BAN::ErrorOr ATADevice::read_sectors(uint64_t lba, uint8_t sector_count, uint8_t* buffer) + { + TRY(m_controller->read(this, lba, sector_count, buffer)); + return {}; + } + + BAN::ErrorOr ATADevice::write_sectors(uint64_t lba, uint8_t sector_count, const uint8_t* buffer) + { + TRY(m_controller->write(this, lba, sector_count, buffer)); + return {}; + } + + uint8_t ATADevice::io_read(uint16_t port) + { + if (port <= 0x07) + return IO::inb(m_base + port); + if (0x10 <= port && port <= 0x11) + return IO::inb(m_ctrl + port - 0x10); + ASSERT_NOT_REACHED(); + } + + void ATADevice::read_buffer(uint16_t port, uint16_t* buffer, size_t words) + { + if (port <= 0x07) + return IO::insw(m_base + port - 0x00, buffer, words); + if (0x10 <= port && port <= 0x11) + return IO::insw(m_ctrl + port - 0x10, buffer, words); + ASSERT_NOT_REACHED(); + } + + void ATADevice::io_write(uint16_t port, uint8_t data) + { + if (port <= 0x07) + return IO::outb(m_base + port, data); + if (0x10 <= port && port <= 0x11) + return IO::outb(m_ctrl + port - 0x10, data); + ASSERT_NOT_REACHED(); + } + + void ATADevice::write_buffer(uint16_t port, const uint16_t* buffer, size_t words) + { + uint16_t io_port = 0; + if (port <= 0x07) + io_port = m_base + port; + if (0x10 <= port && port <= 0x11) + io_port = m_ctrl + port - 0x10; + ASSERT(io_port); + for (size_t i = 0; i < words; i++) + IO::outw(io_port, buffer[i]); + } + + BAN::ErrorOr ATADevice::wait(bool wait_drq) + { + for (uint32_t i = 0; i < 4; i++) + io_read(ATA_PORT_ALT_STATUS); + + uint8_t status = ATA_STATUS_BSY; + while (status & ATA_STATUS_BSY) + status = io_read(ATA_PORT_STATUS); + + while (wait_drq && !(status & ATA_STATUS_DRQ)) + { + if (status & ATA_STATUS_ERR) + return error(); + if (status & ATA_STATUS_DF) + return BAN::Error::from_errno(EIO); + status = io_read(ATA_PORT_STATUS); + } + + return {}; + } + + BAN::Error ATADevice::error() + { + uint8_t err = io_read(ATA_PORT_ERROR); + if (err & ATA_ERROR_AMNF) + return BAN::Error::from_c_string("Address mark not found."); + if (err & ATA_ERROR_TKZNF) + return BAN::Error::from_c_string("Track zero not found."); + if (err & ATA_ERROR_ABRT) + return BAN::Error::from_c_string("Aborted command."); + if (err & ATA_ERROR_MCR) + return BAN::Error::from_c_string("Media change request."); + if (err & ATA_ERROR_IDNF) + return BAN::Error::from_c_string("ID not found."); + if (err & ATA_ERROR_MC) + return BAN::Error::from_c_string("Media changed."); + if (err & ATA_ERROR_UNC) + return BAN::Error::from_c_string("Uncorrectable data error."); + if (err & ATA_ERROR_BBK) + return BAN::Error::from_c_string("Bad Block detected."); + ASSERT_NOT_REACHED(); + } + + dev_t ATADevice::dev() const + { + ASSERT(m_controller); + return m_controller->dev(); + } + + BAN::ErrorOr ATADevice::read(size_t offset, void* buffer, size_t bytes) + { + if (offset % sector_size() || bytes % sector_size()) + return BAN::Error::from_errno(EINVAL); + if (offset == total_size()) + return 0; + TRY(read_sectors(offset / sector_size(), bytes / sector_size(), (uint8_t*)buffer)); + return bytes; + } + +} \ No newline at end of file