summaryrefslogtreecommitdiff
path: root/Kernel/Storage/ATA/AHCI/Port.h
diff options
context:
space:
mode:
authorLiav A <liavalb@gmail.com>2021-11-19 11:52:07 +0200
committerLinus Groh <mail@linusgroh.de>2022-07-19 11:07:34 +0100
commitc001e3f567bb9ceae8b49476ee72a7e5a4b9f37a (patch)
tree08a30ce8838f76b65a209088cb5ecc3d385b5ab3 /Kernel/Storage/ATA/AHCI/Port.h
parenta70e1a0340e683f4e835a47dff843392e5028a4b (diff)
downloadserenity-c001e3f567bb9ceae8b49476ee72a7e5a4b9f37a.zip
Kernel/Storage: Move AHCI and IDE code into new subdirectories
We do that to increase clarity of the major and secondary components in the subsystem. To ensure it's even more understandable, we rename the files to better represent the class within them and to remove redundancy in the name. Also, some includes are removed from the general components of the ATA components' classes.
Diffstat (limited to 'Kernel/Storage/ATA/AHCI/Port.h')
-rw-r--r--Kernel/Storage/ATA/AHCI/Port.h137
1 files changed, 137 insertions, 0 deletions
diff --git a/Kernel/Storage/ATA/AHCI/Port.h b/Kernel/Storage/ATA/AHCI/Port.h
new file mode 100644
index 0000000000..db06200579
--- /dev/null
+++ b/Kernel/Storage/ATA/AHCI/Port.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2021-2022, Liav A. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/OwnPtr.h>
+#include <AK/RefPtr.h>
+#include <AK/WeakPtr.h>
+#include <AK/Weakable.h>
+#include <Kernel/Devices/Device.h>
+#include <Kernel/Interrupts/IRQHandler.h>
+#include <Kernel/Locking/Mutex.h>
+#include <Kernel/Locking/Spinlock.h>
+#include <Kernel/Memory/AnonymousVMObject.h>
+#include <Kernel/Memory/PhysicalPage.h>
+#include <Kernel/Memory/ScatterGatherList.h>
+#include <Kernel/PhysicalAddress.h>
+#include <Kernel/Random.h>
+#include <Kernel/Sections.h>
+#include <Kernel/Storage/ATA/AHCI/Definitions.h>
+#include <Kernel/Storage/ATA/AHCI/InterruptHandler.h>
+#include <Kernel/Storage/ATA/ATADevice.h>
+#include <Kernel/WaitQueue.h>
+
+namespace Kernel {
+
+class AsyncBlockDeviceRequest;
+
+class AHCIInterruptHandler;
+class AHCIPort
+ : public RefCounted<AHCIPort>
+ , public Weakable<AHCIPort> {
+ friend class AHCIController;
+
+public:
+ static ErrorOr<NonnullRefPtr<AHCIPort>> create(AHCIController const&, AHCI::HBADefinedCapabilities, volatile AHCI::PortRegisters&, u32 port_index);
+
+ u32 port_index() const { return m_port_index; }
+ u32 representative_port_index() const { return port_index() + 1; }
+ bool is_operable() const;
+ bool is_atapi_attached() const { return m_port_registers.sig == (u32)AHCI::DeviceSignature::ATAPI; };
+
+ RefPtr<StorageDevice> connected_device() const { return m_connected_device; }
+
+ bool reset();
+ bool initialize_without_reset();
+ void handle_interrupt();
+
+private:
+ ErrorOr<void> allocate_resources_and_initialize_ports();
+
+ bool is_phy_enabled() const { return (m_port_registers.ssts & 0xf) == 3; }
+ bool initialize();
+
+ AHCIPort(AHCIController const&, NonnullRefPtr<Memory::PhysicalPage> identify_buffer_page, AHCI::HBADefinedCapabilities, volatile AHCI::PortRegisters&, u32 port_index);
+
+ ALWAYS_INLINE void clear_sata_error_register() const;
+
+ void eject();
+
+ char const* try_disambiguate_sata_status();
+ void try_disambiguate_sata_error();
+
+ bool initiate_sata_reset();
+ void rebase();
+ void recover_from_fatal_error();
+ bool shutdown();
+ ALWAYS_INLINE void spin_up() const;
+ ALWAYS_INLINE void power_on() const;
+
+ void start_request(AsyncBlockDeviceRequest&);
+ void complete_current_request(AsyncDeviceRequest::RequestResult);
+ bool access_device(AsyncBlockDeviceRequest::RequestType, u64 lba, u8 block_count);
+ size_t calculate_descriptors_count(size_t block_count) const;
+ [[nodiscard]] Optional<AsyncDeviceRequest::RequestResult> prepare_and_set_scatter_list(AsyncBlockDeviceRequest& request);
+
+ ALWAYS_INLINE bool is_interrupts_enabled() const;
+
+ bool spin_until_ready() const;
+
+ bool identify_device();
+
+ ALWAYS_INLINE void start_command_list_processing() const;
+ ALWAYS_INLINE void mark_command_header_ready_to_process(u8 command_header_index) const;
+ ALWAYS_INLINE void stop_command_list_processing() const;
+
+ ALWAYS_INLINE void start_fis_receiving() const;
+ ALWAYS_INLINE void stop_fis_receiving() const;
+
+ ALWAYS_INLINE void set_active_state() const;
+ ALWAYS_INLINE void set_sleep_state() const;
+
+ void set_interface_state(AHCI::DeviceDetectionInitialization);
+
+ Optional<u8> try_to_find_unused_command_header();
+
+ ALWAYS_INLINE bool is_interface_disabled() const { return (m_port_registers.ssts & 0xf) == 4; };
+
+ ALWAYS_INLINE void wait_until_condition_met_or_timeout(size_t delay_in_microseconds, size_t retries, Function<bool(void)> condition_being_met) const;
+
+ // Data members
+
+ EntropySource m_entropy_source;
+ RefPtr<AsyncBlockDeviceRequest> m_current_request;
+ Spinlock m_hard_lock;
+ Mutex m_lock { "AHCIPort"sv };
+
+ mutable bool m_wait_for_completion { false };
+
+ NonnullRefPtrVector<Memory::PhysicalPage> m_dma_buffers;
+ NonnullRefPtrVector<Memory::PhysicalPage> m_command_table_pages;
+ RefPtr<Memory::PhysicalPage> m_command_list_page;
+ OwnPtr<Memory::Region> m_command_list_region;
+ RefPtr<Memory::PhysicalPage> m_fis_receive_page;
+ RefPtr<ATADevice> m_connected_device;
+
+ u32 m_port_index;
+
+ // Note: Ideally the AHCIController should be the only object to hold this data
+ // but because using the m_parent_controller means we need to take a strong ref,
+ // it's probably better to just "cache" this here instead.
+ AHCI::HBADefinedCapabilities const m_hba_capabilities;
+
+ NonnullRefPtr<Memory::PhysicalPage> m_identify_buffer_page;
+
+ volatile AHCI::PortRegisters& m_port_registers;
+ WeakPtr<AHCIController> m_parent_controller;
+ AHCI::PortInterruptStatusBitField m_interrupt_status;
+ AHCI::PortInterruptEnableBitField m_interrupt_enable;
+
+ RefPtr<Memory::ScatterGatherList> m_current_scatter_list;
+ bool m_disabled_by_firmware { false };
+};
+}