blob: ad866054f0c87d15de917c94947397dfa9980666 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
/*
* Copyright (c) 2021, 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/AHCI.h>
#include <Kernel/Storage/AHCIPortHandler.h>
#include <Kernel/Storage/ATADevice.h>
#include <Kernel/WaitQueue.h>
namespace Kernel {
class AsyncBlockDeviceRequest;
class AHCIPortHandler;
class AHCIPort
: public RefCounted<AHCIPort>
, public Weakable<AHCIPort> {
friend class AHCIPortHandler;
friend class AHCIController;
public:
UNMAP_AFTER_INIT static NonnullRefPtr<AHCIPort> create(const AHCIPortHandler&, 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_hot_pluggable() 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();
UNMAP_AFTER_INIT bool initialize_without_reset();
void handle_interrupt();
private:
bool is_phy_enabled() const { return (m_port_registers.ssts & 0xf) == 3; }
bool initialize(SpinlockLocker<Spinlock>&);
UNMAP_AFTER_INIT AHCIPort(const AHCIPortHandler&, volatile AHCI::PortRegisters&, u32 port_index);
ALWAYS_INLINE void clear_sata_error_register() const;
void eject();
const char* try_disambiguate_sata_status();
void try_disambiguate_sata_error();
bool initiate_sata_reset(SpinlockLocker<Spinlock>&);
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(SpinlockLocker<Spinlock>&);
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; };
// Data members
EntropySource m_entropy_source;
RefPtr<AsyncBlockDeviceRequest> m_current_request;
Spinlock m_hard_lock;
Mutex m_lock { "AHCIPort" };
mutable bool m_wait_for_completion { false };
bool m_wait_connect_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;
volatile AHCI::PortRegisters& m_port_registers;
NonnullRefPtr<AHCIPortHandler> m_parent_handler;
AHCI::PortInterruptStatusBitField m_interrupt_status;
AHCI::PortInterruptEnableBitField m_interrupt_enable;
RefPtr<Memory::ScatterGatherList> m_current_scatter_list;
bool m_disabled_by_firmware { false };
};
}
|