From 3e1da2bc90325f1ca9ff1643b49facd3f5cab625 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Fri, 8 Dec 2023 15:05:43 -0800 Subject: [PATCH] [Denali] Add a simpler command method and use it to send identify. --- sys/denali/ahci/ahci_port.cpp | 70 ++++++++++++++++++++++++++++++++++- sys/denali/ahci/ahci_port.h | 1 + sys/denali/ahci/command.cpp | 31 ---------------- sys/denali/ahci/command.h | 22 ++++------- 4 files changed, 76 insertions(+), 48 deletions(-) diff --git a/sys/denali/ahci/ahci_port.cpp b/sys/denali/ahci/ahci_port.cpp index fe148d6..a179515 100644 --- a/sys/denali/ahci/ahci_port.cpp +++ b/sys/denali/ahci/ahci_port.cpp @@ -44,10 +44,21 @@ AhciPort::AhciPort(AhciPortHba* port) : port_struct_(port) { glcr::ErrorCode AhciPort::Identify() { if (IsSata()) { - IdentifyDeviceCommand identify(this); + CommandInfo identify{ + .command = kIdentifyDevice, + .lba = 0, + .sectors = 1, + .paddr = 0, + }; + auto region = + mmth::OwnedMemoryRegion::ContiguousPhysical(0x200, &identify.paddr); ASSIGN_OR_RETURN(auto* sem, IssueCommand(identify)); sem->Wait(); - identify.OnComplete(); + uint16_t* ident = reinterpret_cast(region.vaddr()); + uint32_t* sector_size = reinterpret_cast(ident + 117); + dbgln("Sector size: {}", *sector_size); + uint64_t* lbas = reinterpret_cast(ident + 100); + dbgln("LBA Count: {}", *lbas); } return glcr::OK; } @@ -77,6 +88,61 @@ glcr::ErrorOr AhciPort::IssueCommand(const Command& command) { return &command_signals_[slot]; } +glcr::ErrorOr AhciPort::IssueCommand( + const CommandInfo& command) { + uint64_t slot; + for (slot = 0; slot < 32; slot++) { + if (!(commands_issued_ & (1 << slot))) { + break; + } + } + if (slot == 32) { + dbgln("All slots full"); + return glcr::INTERNAL; + } + + auto* fis = reinterpret_cast( + command_tables_[slot].command_fis); + *fis = HostToDeviceRegisterFis{ + .fis_type = FIS_TYPE_REG_H2D, + .pmp_and_c = 0x80, + .command = command.command, + .featurel = 0, + + .lba0 = static_cast(command.lba & 0xFF), + .lba1 = static_cast((command.lba >> 8) & 0xFF), + .lba2 = static_cast((command.lba >> 16) & 0xFF), + .device = (1 << 6), // ATA LBA Mode + + .lba3 = static_cast((command.lba >> 24) & 0xFF), + .lba4 = static_cast((command.lba >> 32) & 0xFF), + .lba5 = static_cast((command.lba >> 40) & 0xFF), + .featureh = 0, + + .count = command.sectors, + .icc = 0, + .control = 0, + + .reserved = 0, + }; + + command_tables_[slot].prdt[0].region_address = command.paddr; + command_tables_[slot].prdt[0].byte_count = 512 * command.sectors; + + command_list_->command_headers[slot].prd_table_length = 1; + command_list_->command_headers[slot].command = + (sizeof(HostToDeviceRegisterFis) / 2) & 0x1F; + // Set prefetch bit. + command_list_->command_headers[slot].command |= (1 << 7); + + // TODO: Synchronization-wise we need to ensure this is set in the same + // critical section as where we select a slot. + commands_issued_ |= (1 << slot); + port_struct_->command_issue |= (1 << slot); + + return &command_signals_[slot]; +} + void AhciPort::DumpInfo() { dbgln("Comlist: {x}", port_struct_->command_list_base); dbgln("FIS: {x}", port_struct_->fis_base); diff --git a/sys/denali/ahci/ahci_port.h b/sys/denali/ahci/ahci_port.h index dc66de6..646278e 100644 --- a/sys/denali/ahci/ahci_port.h +++ b/sys/denali/ahci/ahci_port.h @@ -24,6 +24,7 @@ class AhciPort { glcr::ErrorCode Identify(); glcr::ErrorOr IssueCommand(const Command& command); + glcr::ErrorOr IssueCommand(const CommandInfo& command); void HandleIrq(); diff --git a/sys/denali/ahci/command.cpp b/sys/denali/ahci/command.cpp index 61a5bb1..e33d804 100644 --- a/sys/denali/ahci/command.cpp +++ b/sys/denali/ahci/command.cpp @@ -19,37 +19,6 @@ void* memcpy(void* dest, const void* src, uint64_t count) { Command::~Command() {} -void IdentifyDeviceCommand::PopulateFis(uint8_t* command_fis) const { - HostToDeviceRegisterFis fis __attribute__((aligned(16))){ - .fis_type = FIS_TYPE_REG_H2D, - .pmp_and_c = 0x80, - .command = kIdentifyDevice, - .device = 0, - }; - - memcpy(command_fis, &fis, sizeof(fis)); -} - -void IdentifyDeviceCommand::PopulatePrdt(PhysicalRegionDescriptor* prdt) const { - prdt[0].region_address = paddr_; - prdt[0].byte_count = 0x200 - 1; - dbgln("paddr: {x}", paddr_); - uint16_t* ident = reinterpret_cast(identify_.vaddr()); - dbgln("vaddr: {x}", identify_.vaddr()); - for (uint32_t i = 0; i < 256; i++) { - ident[i] = 0; - } -} - -void IdentifyDeviceCommand::OnComplete() { - uint16_t* ident = reinterpret_cast(identify_.vaddr()); - uint32_t* sector_size = reinterpret_cast(ident + 117); - dbgln("Sector size: {}", *sector_size); - uint64_t* lbas = reinterpret_cast(ident + 100); - dbgln("LBA Count: {}", *lbas); - // TODO tell the port its sector size. -} - DmaReadCommand::DmaReadCommand(uint64_t lba, uint64_t sector_cnt, uint64_t paddr) : lba_(lba), sector_cnt_(sector_cnt), paddr_(paddr) {} diff --git a/sys/denali/ahci/command.h b/sys/denali/ahci/command.h index 9c1e73f..447c4f4 100644 --- a/sys/denali/ahci/command.h +++ b/sys/denali/ahci/command.h @@ -8,6 +8,13 @@ class AhciPort; +struct CommandInfo { + uint8_t command; + uint64_t lba; + uint16_t sectors; + uint64_t paddr; +}; + class Command { public: Command() = default; @@ -16,21 +23,6 @@ class Command { virtual void PopulatePrdt(PhysicalRegionDescriptor* prdt) const = 0; }; -class IdentifyDeviceCommand : public Command { - public: - IdentifyDeviceCommand(AhciPort* port) : port_(port) {} - virtual void PopulateFis(uint8_t* command_fis) const override; - virtual void PopulatePrdt(PhysicalRegionDescriptor* prdt) const override; - - void OnComplete(); - - private: - AhciPort* port_; - uint64_t paddr_; - mmth::OwnedMemoryRegion identify_ = - mmth::OwnedMemoryRegion::ContiguousPhysical(0x200, &paddr_); -}; - class DmaReadCommand : public Command { public: DmaReadCommand(uint64_t lba, uint64_t sector_cnt, uint64_t dest_paddr);